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