galleria_photo_face_rknn_op.../api_v1/scanner/scan.md
2026-10-03 12:16:58 +02:00

7.2 KiB

scanPhotosUser(userName, db) │ ├── individua: │ photos//original/ │ ├── legge le entry dentro original/ │ ├── prende SOLO le directory │ ├── countFilesUser(userDir) │ └── ricorsivamente guarda tutti i file │ └── conta solo quelli con estensione in SUPPORTED_EXTS │ └── per ogni cartella: scanPhoto(cartella, userName, db, ...) │ └── QUI viene probabilmente deciso cosa fare col singolo file

scanPhotosUser │ │ per ogni cartella ▼ scanPhoto() │ ▼ scanPhotoCartella() │ └── QUI probabilmente avviene la decisione sul file

Quindi scanPhoto(): costruisce il percorso: const absCartella = path.join(userDir, cartella); passa la cartella a scanPhotoCartella(). scanPhotoCartella() riempie newFiles. solo dopo, scanPhoto() manda al server i file presenti in newFiles:

scanCartella.js non decide se la foto è già stata scansionata: decide solo quali file sono candidati alla scansione.

cartella ↓ walk() ricorsivo ↓ è directory? ├─ sì → entra dentro └─ no ↓ estensione supportata? ├─ no → SKIP └─ sì ↓ crea ID deterministico ↓ stat() del file ↓ yield metadata

Il valore di SUPPORTED_EXTS è quindi importante. Lo trovi in: api_v1/config.js La cosa ancora più interessante: l'ID Per ogni file accettato crea:

const id = sha256(${userName}/${cartella}/${fileRelPath});

Quindi l'ID non dipende dal contenuto della foto. Dipende da: user + cartella + percorso relativo

scanPhotoUser ↓ scanPhoto ↓ scanPhotoCartella ↓ scanCartella ↓ per ogni file con estensione supportata ↓ scanPhotoSingle(...) ↓ QUI viene probabilmente deciso: ├── già presente → non fare certe operazioni ├── nuovo → processa └── modificato → eventualmente aggiorna

Quindi non è scanPhotoCartella a decidere se processare o meno la foto. È scanPhotoSingle. 4. Ma c'è un altro meccanismo importante: gli orfani Dopo scanPhotoSingle trovi: idsSet.delete(f.id); Questo significa: "Ho trovato fisicamente questo file durante la scansione, quindi il suo ID non è un orfano." Alla fine: for (const orphanId of idsSet) { log(🔴 Orfano: ${orphanId}); await deleteThumbsById(orphanId); await deleteFromDB(orphanId, user); }

DB all'inizio │ ├── A ├── B └── C ↓ scansione filesystem ↓ trovo A → idsSet.delete(A) trovo C → idsSet.delete(C) ↓ rimane B ↓ B non esiste più sul filesystem ↓ B = ORFANO ↓ cancella thumbnail + DB

Una foto viene presa in considerazione se: si trova dentro una cartella sotto original; è un file, non una directory; la sua estensione è presente in SUPPORTED_EXTS. Poi viene generato un ID: sha256(${userName}/${cartella}/${fileRelPath}) e il file viene passato a: scanPhotoSingle(...)

La decisione è tutta qui Quando trova un file, fa: let prev = await db('photos') .select('id', 'size_bytes', 'mtimeMs', 'fast_hash', 'path') .where({ id }) .first(); Quindi cerca nel DB una foto con lo stesso ID. L'ID, come abbiamo visto prima, è: sha256(${userName}/${cartella}/${fileRelPath}) Quindi normalmente identifica quel preciso percorso del file. Poi calcola: const fastHash = sha256(${st.size}-${st.mtimeMs}); Quindi il contenuto non viene hashato: il "fast hash" dipende solo da: dimensione file + data modifica Le 3 situazioni

  1. Foto nuova Se: if (!prev) cioè non esiste nel DB un record con quell'ID, fa: const meta = await processFile(...) Questa è la parte che legge/elabora veramente la foto. Poi la inserisce nel DB: await db('photos').insert(...) e soprattutto: newFiles.push(meta); Quindi una foto nuova viene processata e considerata newFile.
  2. Foto già presente e invariata Questa è la situazione che probabilmente ti interessava: if (prev.fast_hash === fastHash) { In questo caso NON chiama processFile(). Fa solamente: await db('photos') .where({ id }) .update({ path: f.path, size_bytes: st.size, mtimeMs: st.mtimeMs, fast_hash: fastHash, updated_at: new Date().toISOString(), });

return null; Quindi: Se l'ID esiste e size + mtimeMs sono uguali, la foto viene saltata. Non viene riletta, non vengono rigenerate thumbnail, non viene ricalcolato GPS/location, ecc. Questo è il vero "skip". 3. Foto modificata Se esiste prev, ma: prev.fast_hash !== fastHash allora: log(${prefix} 🟠 Modificato: ${fileName}); e viene nuovamente chiamato: const meta = await processFile(...) Quindi la foto viene riprocessata completamente. C'è però un caso speciale: path cambiato Prima del controllo fast_hash c'è: if (prev && prev.path !== f.path) { log(${prefix} 🟢 Nuovo/Modificato (path changed): ${fileName}); prev = null; } Questo significa: se trovo lo stesso id ma il path nel DB è diverso da quello attuale, tratto il file come nuovo. E quindi finisce qui: if (!prev) { ... await processFile(...) ... await db('photos').insert(...) } Ma qui vedo una possibile anomalia Se prev esiste già nel DB e fai: prev = null; poi fai: await db('photos').insert({ id: meta.id, ... }); Se id è una chiave unica, potresti avere un errore di duplicate key invece di un vero aggiornamento. Però per capire se questo caso è realmente possibile bisogna vedere come viene costruito f.path e come viene gestito il DB.

              TROVO FILE
                  │
                  ▼
          estensione supportata?
             │            │
            NO           SI
             │            │
           SKIP           ▼
                     calcolo ID
                          │
                          ▼
                   cerco ID nel DB
                          │
             ┌────────────┴────────────┐
             │                         │
          non esiste                 esiste
             │                         │
             ▼                         ▼
      processFile()              path diverso?
             │                    │         │
             │                   SI        NO
             │                    │         │
             │                    ▼         ▼
             │                  prev=null  confronto
             │                              fastHash
             │                           │          │
             │                         UGUALE    DIVERSO
             │                           │          │
             │                           ▼          ▼
             │                         SKIP     processFile()
             │                                      │
             └──────────────────────────────────────┘