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:
@@ -17,6 +17,12 @@ type local struct {
|
||||
root string
|
||||
}
|
||||
|
||||
// NewLocal builds the local-disk backend explicitly, whichever backend is
|
||||
// active — `photo-api sync` needs both sides at once.
|
||||
func NewLocal(root string) (Storage, error) {
|
||||
return newLocal(root)
|
||||
}
|
||||
|
||||
func newLocal(root string) (*local, error) {
|
||||
if err := os.MkdirAll(root, 0o755); err != nil {
|
||||
return nil, fmt.Errorf("create storage dir %s: %w", root, err)
|
||||
@@ -74,6 +80,21 @@ func (l *local) Open(_ context.Context, key string) (io.ReadCloser, int64, error
|
||||
return f, info.Size(), nil
|
||||
}
|
||||
|
||||
func (l *local) Stat(_ context.Context, key string) (int64, error) {
|
||||
p, err := l.path(key)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
info, err := os.Stat(p)
|
||||
if os.IsNotExist(err) {
|
||||
return 0, ErrNotExist
|
||||
}
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return info.Size(), nil
|
||||
}
|
||||
|
||||
func (l *local) Delete(_ context.Context, key string) error {
|
||||
p, err := l.path(key)
|
||||
if err != nil {
|
||||
|
||||
Reference in New Issue
Block a user