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

117 lines
3.1 KiB
JavaScript

const path = require('path');
const fsp = require('fs/promises');
const ExifReader = require('exifreader');
const sharp = require('sharp');
const { sha256, inferMimeFromExt, parseExifDateUtc } = require('./utils');
const { extractGpsFromExif, extractGpsWithExiftool } = require('./gps');
const { createVideoThumbnail, createThumbnails } = require('./thumbs');
const { probeVideo } = require('./video');
const loc = require('../geo.js');
const { WEB_ROOT, PATH_FULL } = require('../config');
async function processFile(userName, cartella, fileRelPath, absPath, ext, st) {
const isVideo = ['.mp4', '.mov', '.m4v'].includes(ext);
console.log(
`PROCESSING → user=${userName} | cartella=${cartella} | file=${fileRelPath}`
);
const thumbBase = path.join(
WEB_ROOT,
'photos',
userName,
'thumbs',
cartella,
path.dirname(fileRelPath)
);
await fsp.mkdir(thumbBase, { recursive: true });
const baseName = path.parse(fileRelPath).name;
const absThumbMin = path.join(thumbBase, `${baseName}_min.jpg`);
const absThumbAvg = path.join(thumbBase, `${baseName}_avg.jpg`);
if (isVideo) {
await createVideoThumbnail(absPath, absThumbMin, absThumbAvg);
} else {
await createThumbnails(absPath, absThumbMin, absThumbAvg);
}
let tags = {};
try { tags = await ExifReader.load(absPath, { expanded: true }); } catch {}
const timeRaw = tags?.exif?.DateTimeOriginal?.value?.[0] || null;
const takenAtIso = parseExifDateUtc(timeRaw);
let gps = isVideo
? await extractGpsWithExiftool(absPath)
: extractGpsFromExif(tags);
let width = null, height = null, duration = null;
if (isVideo) {
const info = await probeVideo(absPath);
const stream = info.streams?.find(s => s.width && s.height);
if (stream) {
width = stream.width;
height = stream.height;
}
duration = info.format?.duration || null;
} else {
try {
const meta = await sharp(absPath).metadata();
width = meta.width || null;
height = meta.height || null;
} catch {}
}
const mime_type = inferMimeFromExt(ext);
const id = sha256(`${userName}/${cartella}/${fileRelPath}`);
const location = gps ? await loc(gps.lng, gps.lat) : null;
//
// --- GESTIONE PATH FULL / RELATIVI ---
//
// relativi (comportamento attuale)
const relPath = fileRelPath;
const relThub1 = fileRelPath.replace(/\.[^.]+$/, '_min.jpg');
const relThub2 = fileRelPath.replace(/\.[^.]+$/, '_avg.jpg');
// completi (solo se PATH_FULL = true)
const fullPath = PATH_FULL
? path.posix.join('/photos', userName, cartella, fileRelPath)
: relPath;
const fullThub1 = PATH_FULL
? path.posix.join('/photos', userName, 'thumbs', cartella, relThub1)
: relThub1;
const fullThub2 = PATH_FULL
? path.posix.join('/photos', userName, 'thumbs', cartella, relThub2)
: relThub2;
return {
id,
user: userName,
cartella,
path: fullPath,
thub1: fullThub1,
thub2: fullThub2,
gps,
data: timeRaw,
taken_at: takenAtIso,
mime_type,
width,
height,
size_bytes: st.size,
mtimeMs: st.mtimeMs,
duration: isVideo ? duration : null,
location
};
}
module.exports = processFile;