233 lines
6.1 KiB
JavaScript
233 lines
6.1 KiB
JavaScript
// 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;
|