Files
photog/watcher.go
T

76 lines
1.5 KiB
Go
Raw Normal View History

2026-07-02 00:53:17 +02:00
package main
import (
"log"
"path/filepath"
"strings"
"time"
"github.com/fsnotify/fsnotify"
)
type Watcher struct {
w *fsnotify.Watcher
g *Generator
done chan struct{}
}
func NewWatcher(dir string, g *Generator) (*Watcher, error) {
w, err := fsnotify.NewWatcher()
if err != nil {
return nil, err
}
if err := w.Add(dir); err != nil {
w.Close()
return nil, err
}
return &Watcher{w: w, g: g, done: make(chan struct{})}, nil
}
// Watch blocks, watching for changes and triggering rebuilds.
// Rapid events (e.g. scp writing an image then its sidecar) are debounced
// with a 500 ms window so only one rebuild fires per logical upload.
func (w *Watcher) Watch() {
var timer *time.Timer
rebuild := func() {
if err := w.g.Build(); err != nil {
log.Printf("rebuild: %v", err)
}
}
for {
select {
case event, ok := <-w.w.Events:
if !ok {
return
}
if !isRelevant(event.Name) {
continue
}
if event.Has(fsnotify.Create) || event.Has(fsnotify.Write) || event.Has(fsnotify.Remove) {
if timer != nil {
timer.Stop()
}
timer = time.AfterFunc(500*time.Millisecond, rebuild)
}
case err, ok := <-w.w.Errors:
if !ok {
return
}
log.Printf("watcher: %v", err)
case <-w.done:
return
}
}
}
func (w *Watcher) Close() {
close(w.done)
w.w.Close()
}
func isRelevant(name string) bool {
ext := strings.ToLower(filepath.Ext(name))
return ext == ".jpg" || ext == ".jpeg" || ext == ".png" || ext == ".toml"
}