99 lines
No EOL
3.4 KiB
JavaScript
99 lines
No EOL
3.4 KiB
JavaScript
// scanner/scanCartella.js
|
||
const path = require('path');
|
||
const fsp = require('fs/promises');
|
||
const processFile = require('./processFile');
|
||
const { sha256 } = require('./utils');
|
||
const { SUPPORTED_EXTS } = require('../config');
|
||
|
||
/**
|
||
* Scansiona ricorsivamente una cartella e ritorna SOLO i cambiamenti
|
||
* (nuovi/modificati) rispetto a previousIndex (mappa { id: meta }).
|
||
*
|
||
* @param {string} userName - Nome utente (es. "Fabio" o "Common")
|
||
* @param {string} cartella - Nome della cartella logica sotto "original" (es. "2017Irlanda19-29ago")
|
||
* @param {string} absCartella - Percorso assoluto della cartella da scansionare (p.es. .../photos/<Utente>/original/<cartella>)
|
||
* @param {Object} previousIndex- Mappa dell'indice precedente: { <id>: meta }
|
||
* @returns {Promise<Array<Object>>} changes - Lista dei soli meta cambiati o nuovi
|
||
*/
|
||
async function scanCartella(userName, cartella, absCartella, previousIndex) {
|
||
const changes = [];
|
||
|
||
async function walk(currentAbs, relPath = '') {
|
||
let entries = [];
|
||
try {
|
||
entries = await fsp.readdir(currentAbs, { withFileTypes: true });
|
||
} catch (err) {
|
||
// Cartella non leggibile: logga e prosegui (non bloccare la scansione globale)
|
||
console.error(`[SCAN] Impossibile leggere: ${currentAbs} - ${err.message}`);
|
||
return;
|
||
}
|
||
|
||
for (const e of entries) {
|
||
const absPath = path.join(currentAbs, e.name);
|
||
|
||
if (e.isDirectory()) {
|
||
await walk(absPath, path.join(relPath, e.name));
|
||
continue;
|
||
}
|
||
|
||
// Filtra estensioni non supportate
|
||
const ext = path.extname(e.name).toLowerCase();
|
||
if (!SUPPORTED_EXTS.has(ext)) continue;
|
||
|
||
// Percorso relativo POSIX (usato per mantenere slash '/')
|
||
const fileRelPath = relPath ? `${relPath}/${e.name}` : e.name;
|
||
|
||
// ID deterministico: user/cartella/relPath
|
||
const id = sha256(`${userName}/${cartella}/${fileRelPath}`);
|
||
|
||
// Confronto con indice precedente per saltare "unchanged"
|
||
let st;
|
||
try {
|
||
st = await fsp.stat(absPath);
|
||
} catch (err) {
|
||
// File sparito o non accessibile: salta
|
||
console.warn(`[SCAN] stat fallita: ${absPath} - ${err.message}`);
|
||
continue;
|
||
}
|
||
|
||
const prev = previousIndex[id];
|
||
const unchanged =
|
||
prev &&
|
||
prev.size_bytes === st.size &&
|
||
prev.mtimeMs === st.mtimeMs;
|
||
|
||
if (unchanged) continue; // nulla da aggiornare
|
||
|
||
// Estrae metadati (EXIF, mime, dimensioni, thumbs, ecc.)
|
||
const meta = await processFile(
|
||
userName,
|
||
cartella,
|
||
fileRelPath,
|
||
absPath,
|
||
ext,
|
||
st
|
||
);
|
||
|
||
// ID sempre presente
|
||
meta.id = id;
|
||
|
||
// 🔧 Canonicalizza SEMPRE il path pubblicato nell’index:
|
||
// /photos/<Utente>/original/<cartella>/<fileRelPath>
|
||
{
|
||
// Normalizza separatori e rimuove eventuali leading-slash multipli
|
||
const relPosix = String(fileRelPath).replace(/\\/g, '/').replace(/^\/+/, '');
|
||
// Costruisci il path canonico e comprimi eventuali '//' in '/'
|
||
const canonical = `/photos/${userName}/original/${cartella}/${relPosix}`.replace(/\/+/g, '/');
|
||
meta.path = canonical;
|
||
// NB: thub1/thub2 rimangono quelli prodotti da processFile (ok per immagini e video)
|
||
}
|
||
|
||
changes.push(meta);
|
||
}
|
||
}
|
||
|
||
await walk(absCartella);
|
||
return changes;
|
||
}
|
||
|
||
module.exports = scanCartella; |