photo_server_json_flutter_c.../api_v1/scanner/scanPhoto.js
2026-03-05 17:07:30 +01:00

134 lines
No EOL
4.6 KiB
JavaScript

// scanner/scanPhoto.js
const path = require('path');
const fsp = require('fs/promises');
const { loadPreviousIndex, saveIndex } = require('./indexStore');
const scanUserRoot = require('./scanUser');
const postWithAuth = require('./postWithAuth');
const {
WEB_ROOT,
SEND_PHOTOS,
BASE_URL,
WRITE_INDEX,
} = require('../config');
const COMMON = 'Common'; // Nome canonico e case-sensitive per la shared folder
/**
* Restituisce la prima directory esistente tra le candidate
* @param {string[]} candidates
* @returns {Promise<string|null>}
*/
async function firstExistingDir(candidates) {
for (const dir of candidates) {
try {
const st = await fsp.stat(dir);
if (st.isDirectory()) return dir;
} catch { /* ignore */ }
}
return null;
}
/**
* Scansione foto con indice separato:
* - Carica indice precedente (mappa { id: meta })
* - Produce SOLO i cambiamenti (nuovi/modificati)
* - Merge e salvataggio atomico dell'indice
* - POST verso /photos solo del delta (se abilitato)
* - Admin: include la cartella "Common"
*
* Nota path: usiamo un path ASSOLUTO per <root>/public/photos
* partendo da .../api_v1/scanner -> '..', '..' per salire alla root del progetto.
*/
async function scanPhoto(dir, userName) {
try {
const previousIndexMap = await loadPreviousIndex();
const nextIndexMap = { ...previousIndexMap };
// Path assoluto alla radice photos (es: <root>/public/photos)
const photosRoot = path.resolve(__dirname, '..', '..', WEB_ROOT, 'photos');
let changes = [];
if (userName === 'Admin') {
// 1) Scansiona TUTTI gli utenti tranne la/e cartella/e common
let entries = [];
try {
entries = await fsp.readdir(photosRoot, { withFileTypes: true });
} catch (e) {
console.error(`[SCAN] photosRoot non accessibile: ${photosRoot}`, e.message);
entries = [];
}
for (const e of entries) {
if (!e.isDirectory()) continue;
// salta qualunque "common" (qualunque casing) per non doppiare
if (e.name.toLowerCase() === COMMON.toLowerCase()) continue;
const userDir = path.join(photosRoot, e.name, 'original');
try {
const st = await fsp.stat(userDir);
if (!st.isDirectory()) continue;
} catch {
continue;
}
const userChanges = await scanUserRoot(e.name, userDir, previousIndexMap);
for (const m of userChanges) nextIndexMap[m.id] = m;
changes.push(...userChanges);
}
// 2) Scansiona la cartella COMMON (case strict), con fallback legacy (solo lettura) a 'common'
const commonPreferred = path.join(photosRoot, COMMON, 'original'); // .../photos/Common/original
const commonLegacy = path.join(photosRoot, 'common', 'original'); // .../photos/common/original (legacy)
const commonDir = await firstExistingDir([commonPreferred, commonLegacy]);
if (commonDir) {
// Forziamo SEMPRE userName = 'Common' per ID/thumbnails coerenti in 'Common'
const commonChanges = await scanUserRoot(COMMON, commonDir, previousIndexMap);
for (const m of commonChanges) nextIndexMap[m.id] = m;
changes.push(...commonChanges);
console.log(`[SCAN] Common indicizzati da ${commonDir}: +${commonChanges.length}`);
} else {
console.log(`[SCAN] Nessuna cartella "${COMMON}" trovata sotto ${photosRoot} (atteso: ${commonPreferred})`);
}
} else {
// Non-Admin (per completezza; in server.js /scan è Admin-only)
const userDir = path.join(photosRoot, userName, 'original');
try {
const st = await fsp.stat(userDir);
if (st.isDirectory()) {
const userChanges = await scanUserRoot(userName, userDir, previousIndexMap);
for (const m of userChanges) nextIndexMap[m.id] = m;
changes.push(...userChanges);
}
} catch {
// utente senza dir 'original' -> nessuna modifica
}
}
// Salva indice (mappa) in modo atomico
if (WRITE_INDEX) {
await saveIndex(nextIndexMap);
}
// POST solo dei cambiamenti (delta)
if (SEND_PHOTOS && BASE_URL && changes.length) {
for (const p of changes) {
try {
await postWithAuth(`${BASE_URL}/photos`, p);
} catch (err) {
console.error('Errore invio:', err.message);
}
}
}
console.log(`SCAN COMPLETATA per utente ${userName}: ${changes.length} file aggiornati`);
return changes;
} catch (e) {
console.error('Errore generale scanPhoto:', e);
throw e;
}
}
module.exports = scanPhoto;