122 lines
2.6 KiB
Go
122 lines
2.6 KiB
Go
package gallery
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"fmt"
|
|
"hash/fnv"
|
|
"log/slog"
|
|
"os"
|
|
"path"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/valkey-io/valkey-go"
|
|
)
|
|
|
|
type Image struct {
|
|
UID string
|
|
X int
|
|
Y int
|
|
Width int
|
|
Height int
|
|
}
|
|
|
|
const (
|
|
imagesKey = "gallery:images:list"
|
|
hashKey = "gallery:images:hash"
|
|
)
|
|
|
|
func (s *Service) autoRefresh() {
|
|
t := time.NewTicker(time.Minute)
|
|
for {
|
|
ctx, cancle := context.WithTimeout(context.Background(), time.Minute)
|
|
|
|
if err := s.assembleImageList(ctx); err != nil {
|
|
slog.Error("error while refreshing gallery", "err", err)
|
|
}
|
|
cancle()
|
|
<-t.C
|
|
}
|
|
}
|
|
|
|
func (s *Service) assembleImageList(ctx context.Context) error {
|
|
files, err := s.readDirRecursive(s.cfg.Path)
|
|
if err != nil {
|
|
return fmt.Errorf("could not read contents of %s: %w", s.cfg.Path, err)
|
|
}
|
|
|
|
savedHash, _ := s.cache.Do(ctx, s.cache.B().Get().Key(hashKey).Build()).AsBytes()
|
|
|
|
newHash := hashImageList(files)
|
|
|
|
if bytes.Equal(savedHash, newHash) {
|
|
slog.Debug("images up to date no refreshing of gallery", "savedHash", savedHash, "newHash", newHash)
|
|
return nil
|
|
}
|
|
|
|
slog.Info("starting gallery refresh")
|
|
defer slog.Info("gallery refresh completed")
|
|
|
|
imgs := make([]Image, 0, len(files))
|
|
for _, file := range files {
|
|
if strings.HasSuffix(file.Name(), ".md") {
|
|
continue
|
|
}
|
|
|
|
imagePath := path.Join(s.cfg.Path, file.Name())
|
|
img, err := s.img.GetImage(imagePath)
|
|
if err != nil || img.Image == nil {
|
|
slog.Warn("could not get image for gallery", "err", err, "img", img)
|
|
continue
|
|
}
|
|
|
|
uid, err := img.UID()
|
|
if err != nil {
|
|
continue
|
|
}
|
|
|
|
w := img.Bounds().Dx()
|
|
h := img.Bounds().Dy()
|
|
|
|
// FIX 2: Defensive check to guard against unreadable/corrupted image boundaries
|
|
if w <= 0 || h <= 0 {
|
|
slog.Warn("skipping image with zero or negative dimensions", "path", imagePath, "w", w, "h", h)
|
|
continue
|
|
}
|
|
|
|
imgs = append(imgs, Image{
|
|
UID: uid,
|
|
Width: w,
|
|
Height: h,
|
|
})
|
|
}
|
|
|
|
if err = s.cache.Do(ctx, s.cache.B().Set().Key(hashKey).Value(valkey.BinaryString(newHash)).Build()).Error(); err != nil {
|
|
return err
|
|
}
|
|
|
|
if err = s.cache.Do(ctx, s.cache.B().Set().Key(imagesKey).Value(valkey.JSON(imgs)).Build()).Error(); err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func hashImageList(files []os.FileInfo) []byte {
|
|
h := fnv.New128()
|
|
|
|
for _, file := range files {
|
|
fmt.Fprint(h, file.ModTime())
|
|
fmt.Fprint(h, file.Size())
|
|
fmt.Fprint(h, file.Name())
|
|
}
|
|
|
|
return h.Sum([]byte{})
|
|
}
|
|
|
|
func (s *Service) GetImages(ctx context.Context) (images []Image, err error) {
|
|
err = s.cache.Do(ctx, s.cache.B().Get().Key(imagesKey).Build()).DecodeJSON(&images)
|
|
return
|
|
}
|