lens @ cff5600c8abebd1ce988b2185c07e998c4a1d483

 1package worker
 2
 3import (
 4	"context"
 5	"crypto/md5"
 6	"encoding/hex"
 7	"io/fs"
 8	"path/filepath"
 9
10	"github.com/gabriel-vasile/mimetype"
11
12	"git.sr.ht/~gabrielgio/img/pkg/components/media"
13)
14
15type (
16	FileScanner struct {
17		root       string
18		repository media.Repository
19	}
20)
21
22var _ ChanProcessor[string] = &FileScanner{}
23
24func NewFileScanner(root string, repository media.Repository) *FileScanner {
25	return &FileScanner{
26		root:       root,
27		repository: repository,
28	}
29}
30
31func (f *FileScanner) Query(ctx context.Context) (<-chan string, error) {
32	c := make(chan string)
33	go func() {
34		defer close(c)
35		_ = filepath.Walk(f.root, func(path string, info fs.FileInfo, err error) error {
36			select {
37			case <-ctx.Done():
38				return filepath.SkipAll
39			default:
40			}
41
42			if info.IsDir() && filepath.Base(info.Name())[0] == '.' {
43				return filepath.SkipDir
44			}
45
46			if info.IsDir() {
47				return nil
48			}
49
50			if filepath.Ext(info.Name()) != ".jpg" &&
51				filepath.Ext(info.Name()) != ".jpeg" &&
52				filepath.Ext(info.Name()) != ".png" {
53				return nil
54			}
55			c <- path
56			return nil
57		})
58	}()
59	return c, nil
60}
61
62func (f *FileScanner) Process(ctx context.Context, path string) error {
63	hash := md5.Sum([]byte(path))
64	str := hex.EncodeToString(hash[:])
65	name := filepath.Base(path)
66
67	exists, errResp := f.repository.Exists(ctx, str)
68	if errResp != nil {
69		return errResp
70	}
71
72	if exists {
73		return nil
74	}
75
76	mime, errResp := mimetype.DetectFile(path)
77	if errResp != nil {
78		return errResp
79	}
80
81	return f.repository.Create(ctx, &media.CreateMedia{
82		Name:     name,
83		Path:     path,
84		PathHash: str,
85		MIMEType: mime.String(),
86	})
87}