117 lines
3.1 KiB
JavaScript
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;
|