ok
|
|
@ -8,35 +8,63 @@ const { SUPPORTED_EXTS } = require('../config');
|
||||||
/**
|
/**
|
||||||
* Scansiona ricorsivamente una cartella e ritorna SOLO i cambiamenti
|
* Scansiona ricorsivamente una cartella e ritorna SOLO i cambiamenti
|
||||||
* (nuovi/modificati) rispetto a previousIndex (mappa { id: meta }).
|
* (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) {
|
async function scanCartella(userName, cartella, absCartella, previousIndex) {
|
||||||
const changes = [];
|
const changes = [];
|
||||||
|
|
||||||
async function walk(currentAbs, relPath = '') {
|
async function walk(currentAbs, relPath = '') {
|
||||||
const entries = await fsp.readdir(currentAbs, { withFileTypes: true });
|
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) {
|
for (const e of entries) {
|
||||||
const absPath = path.join(currentAbs, e.name);
|
const absPath = path.join(currentAbs, e.name);
|
||||||
|
|
||||||
if (e.isDirectory()) {
|
if (e.isDirectory()) {
|
||||||
await walk(absPath, path.join(relPath, e.name));
|
await walk(absPath, path.join(relPath, e.name));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Filtra estensioni non supportate
|
||||||
const ext = path.extname(e.name).toLowerCase();
|
const ext = path.extname(e.name).toLowerCase();
|
||||||
if (!SUPPORTED_EXTS.has(ext)) continue;
|
if (!SUPPORTED_EXTS.has(ext)) continue;
|
||||||
|
|
||||||
|
// Percorso relativo POSIX (usato per mantenere slash '/')
|
||||||
const fileRelPath = relPath ? `${relPath}/${e.name}` : e.name;
|
const fileRelPath = relPath ? `${relPath}/${e.name}` : e.name;
|
||||||
|
|
||||||
|
// ID deterministico: user/cartella/relPath
|
||||||
const id = sha256(`${userName}/${cartella}/${fileRelPath}`);
|
const id = sha256(`${userName}/${cartella}/${fileRelPath}`);
|
||||||
|
|
||||||
const st = await fsp.stat(absPath);
|
// Confronto con indice precedente per saltare "unchanged"
|
||||||
const prev = previousIndex[id];
|
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 =
|
const unchanged =
|
||||||
prev &&
|
prev &&
|
||||||
prev.size_bytes === st.size &&
|
prev.size_bytes === st.size &&
|
||||||
prev.mtimeMs === st.mtimeMs;
|
prev.mtimeMs === st.mtimeMs;
|
||||||
|
|
||||||
if (unchanged) continue; // NOTE: skip "unchanged"
|
if (unchanged) continue; // nulla da aggiornare
|
||||||
|
|
||||||
|
// Estrae metadati (EXIF, mime, dimensioni, thumbs, ecc.)
|
||||||
const meta = await processFile(
|
const meta = await processFile(
|
||||||
userName,
|
userName,
|
||||||
cartella,
|
cartella,
|
||||||
|
|
@ -46,7 +74,20 @@ async function scanCartella(userName, cartella, absCartella, previousIndex) {
|
||||||
st
|
st
|
||||||
);
|
);
|
||||||
|
|
||||||
meta.id = id; // id sempre presente
|
// 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);
|
changes.push(meta);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 4.2 MiB After Width: | Height: | Size: 4.2 MiB |
|
Before Width: | Height: | Size: 4.2 MiB After Width: | Height: | Size: 4.2 MiB |
|
Before Width: | Height: | Size: 4.2 MiB After Width: | Height: | Size: 4.2 MiB |
|
Before Width: | Height: | Size: 4.2 MiB After Width: | Height: | Size: 4.2 MiB |
|
Before Width: | Height: | Size: 4.3 MiB After Width: | Height: | Size: 4.3 MiB |
|
Before Width: | Height: | Size: 4.2 MiB After Width: | Height: | Size: 4.2 MiB |
|
Before Width: | Height: | Size: 4.5 MiB After Width: | Height: | Size: 4.5 MiB |
|
Before Width: | Height: | Size: 4.6 MiB After Width: | Height: | Size: 4.6 MiB |
|
Before Width: | Height: | Size: 4.5 MiB After Width: | Height: | Size: 4.5 MiB |