package scanner import ( "context" "io/fs" "mime" "path/filepath" "git.sr.ht/~gabrielgio/img/pkg/database/repository" "git.sr.ht/~gabrielgio/img/pkg/fileop" "git.sr.ht/~gabrielgio/img/pkg/list" "git.sr.ht/~gabrielgio/img/pkg/worker" ) type ( FileScanner struct { mediaRepository repository.MediaRepository userRepository repository.UserRepository } ) var _ worker.ChanProcessor[string] = &FileScanner{} func NewFileScanner( mediaRepository repository.MediaRepository, userRepository repository.UserRepository, ) *FileScanner { return &FileScanner{ mediaRepository: mediaRepository, userRepository: userRepository, } } func (f *FileScanner) Query(ctx context.Context) (<-chan string, error) { c := make(chan string) users, err := f.userRepository.List(ctx) if err != nil { return nil, err } // TODO: de duplicate file paths paths := list.Map(users, func(u *repository.User) string { return u.Path }) go func(paths []string) { defer close(c) for _, p := range paths { _ = filepath.Walk(p, func(path string, info fs.FileInfo, err error) error { select { case <-ctx.Done(): return filepath.SkipAll default: } if info == nil { return nil } if info.IsDir() && filepath.Base(info.Name())[0] == '.' { return filepath.SkipDir } if info.IsDir() { return nil } c <- path return nil }) } }(paths) return c, nil } func (f *FileScanner) Process(ctx context.Context, path string) error { mimetype := mime.TypeByExtension(filepath.Ext(path)) supported := fileop.IsMimeTypeSupported(mimetype) if !supported { return nil } hash := fileop.GetHashFromPath(path) exists, err := f.mediaRepository.Exists(ctx, hash) if err != nil { return err } if exists { return nil } return f.mediaRepository.Create(ctx, &repository.CreateMedia{ Name: filepath.Base(path), Path: path, PathHash: hash, MIMEType: mimetype, }) }