Add photo content-hash dedup and local↔S3 library sync.
Uploads skip per-gallery duplicates, checksums can be backfilled, and STORAGE_BACKEND plus sync tooling make switching storage backends safe.
This commit is contained in:
@@ -0,0 +1,31 @@
|
||||
// Package checksum defines the content hash used to spot duplicate photos and
|
||||
// the backfill that fills it in for photos uploaded before it existed.
|
||||
//
|
||||
// The hash is sha256 over the untouched original bytes, hex encoded, stored in
|
||||
// photos_photos.checksum. Duplicate scope is one gallery — the unique index is
|
||||
// on (gallery_id, checksum) — so the same image may still live in several
|
||||
// galleries, each with its own row and its own stored object.
|
||||
package checksum
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"hash"
|
||||
"io"
|
||||
)
|
||||
|
||||
// New returns a fresh hasher. Upload hashes as it spools the body, so it needs
|
||||
// the writer rather than a finished reader.
|
||||
func New() hash.Hash { return sha256.New() }
|
||||
|
||||
// Format renders a hasher's digest the way it is stored.
|
||||
func Format(h hash.Hash) string { return hex.EncodeToString(h.Sum(nil)) }
|
||||
|
||||
// Sum reads r to EOF and returns its digest.
|
||||
func Sum(r io.Reader) (string, error) {
|
||||
h := New()
|
||||
if _, err := io.Copy(h, r); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return Format(h), nil
|
||||
}
|
||||
Reference in New Issue
Block a user