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}