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;