// api_v1/scanner/scanFile.js const path = require('path'); const fsp = require('fs/promises'); const { sha256 } = require('./utils'); const { SUPPORTED_EXTS } = require('../config'); const { log } = require('./logger'); /** * scanFile: genera informazioni su UN singolo file * Restituisce lo stesso formato di scanCartella, ma senza recursion. * * Parametri: * - userName * - cartella * - absFile (percorso assoluto del file) * - db (opzionale) */ async function scanFileEntry(userName, cartella, absFile, db) { const ext = path.extname(absFile).toLowerCase(); if (!SUPPORTED_EXTS.has(ext)) { log(`⛔ Estensione non supportata: ${ext}`); return null; } const name = path.basename(absFile); const relPath = name; // singolo file → niente struttura ricorsiva let st; try { st = await fsp.stat(absFile); } catch { log(`⛔ Impossibile leggere stat per ${absFile}`); return null; } const id = sha256(`${userName}/${cartella}/${relPath}`); log(`📄 scanFile → user=${userName} cartella=${cartella} file=${name} id=${id}`); return { id, user: userName, cartella, name, relPath, absPath: absFile, ext, stat: st, path: `/photos/${userName}/original/${cartella}/${relPath}` }; } async function scanFile(userName, cartella, absFile, db) { const f = await scanFile(user, cart, absFile); const fileName = f.name; const id = f.id; const st = f.stat; let prev = await db("photos") .select("id", "size_bytes", "mtimeMs", "_indexHash", "fast_hash", "path") .where({ id }) .first(); if (prev && LOG_VERBOSE) { log(`${prefix} ⚪ Invariato: ${fileName}`); } const fastHash = sha256(`${st.size}-${st.mtimeMs}`); // --------------------------------------------------------- // PATH CAMBIATO = NUOVO FILE // --------------------------------------------------------- if (prev && prev.path !== f.path) { log(`${prefix} 🟢 Nuovo/Modificato: ${fileName}`); prev = null; } // --------------------------------------------------------- // NUOVO FILE // --------------------------------------------------------- if (!prev) { log(`${prefix} 🟢 Nuovo/Modificato: ${fileName}`); const meta = await processFile( user, cartella, f.relPath, f.absPath, f.ext, st ); meta.id = id; meta.path = f.path; // INSERT CORRETTO (senza colonna gps) await db("photos").insert({ id: meta.id, user, cartella, name: meta.name, path: meta.path, thub1: meta.thub1, thub2: meta.thub2, mime_type: meta.mime_type, width: meta.width, height: meta.height, rotation: meta.rotation, size_bytes: meta.size_bytes, mtimeMs: meta.mtimeMs, duration_ms: meta.duration_ms, taken_at: meta.taken_at, data: meta.data, lat: meta.gps?.lat ?? null, lon: meta.gps?.lng ?? null, alt: meta.gps?.alt ?? null, location: meta.location ? JSON.stringify(meta.location) : null, _indexHash: meta._indexHash, fast_hash: fastHash }); await db('photo_changes').insert({ photo_id: meta.id, user, change_type: 'added', timestamp: new Date().toISOString() }); newFiles.push(meta); //log(`🟢 [PUSH newFiles] id=${meta.id} path=${meta.path}`); continue; } // --------------------------------------------------------- // FAST-SIZE-SKIP // --------------------------------------------------------- if (prev.size_bytes === st.size) { //log(`🔵 [FAST-SIZE-SKIP] id=${id}`); await db("photos") .where({ id }) .update({ path: f.path, size_bytes: st.size, mtimeMs: st.mtimeMs, fast_hash: fastHash }); continue; } // --------------------------------------------------------- // FAST-HASH-SKIP // --------------------------------------------------------- if (prev.fast_hash === fastHash) { //log(`🔵 [FAST-HASH-SKIP] id=${id}`); await db("photos") .where({ id }) .update({ path: f.path, size_bytes: st.size, mtimeMs: st.mtimeMs }); continue; } // --------------------------------------------------------- // MODIFICATO // --------------------------------------------------------- //log(`🟠 [FULL-SCAN] id=${id}`); log(`${prefix} 🟠 Nuovo/Modificato: ${fileName}`); const meta = await processFile( user, cartella, f.relPath, f.absPath, f.ext, st ); meta.id = id; meta.path = f.path; await db("photos") .insert({ id: meta.id, user, cartella, name: meta.name, path: meta.path, thub1: meta.thub1, thub2: meta.thub2, mime_type: meta.mime_type, width: meta.width, height: meta.height, rotation: meta.rotation, size_bytes: meta.size_bytes, mtimeMs: meta.mtimeMs, duration_ms: meta.duration_ms, taken_at: meta.taken_at, data: meta.data, lat: meta.gps?.lat ?? null, lon: meta.gps?.lng ?? null, alt: meta.gps?.alt ?? null, location: meta.location ? JSON.stringify(meta.location) : null, _indexHash: meta._indexHash, fast_hash: fastHash }) .onConflict("id") .merge(); await db('photo_changes').insert({ photo_id: meta.id, user, change_type: 'updated', timestamp: new Date().toISOString() }); newFiles.push(meta); log(`${prefix} 🟠 Nuovo/Modificato al server ${fileName}`); } } } module.exports = scanFile;