1package scanner
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 "git.sr.ht/~gabrielgio/img/pkg/list"
12 "git.sr.ht/~gabrielgio/img/pkg/worker"
13)
14
15type (
16 FileScanner struct {
17 mediaRepository repository.MediaRepository
18 userRepository repository.UserRepository
19 }
20)
21
22var _ worker.ChanProcessor[string] = &FileScanner{}
23
24func NewFileScanner(
25 mediaRepository repository.MediaRepository,
26 userRepository repository.UserRepository,
27) *FileScanner {
28 return &FileScanner{
29 mediaRepository: mediaRepository,
30 userRepository: userRepository,
31 }
32}
33
34func (f *FileScanner) Query(ctx context.Context) (<-chan string, error) {
35 c := make(chan string)
36
37 users, err := f.userRepository.List(ctx)
38 if err != nil {
39 return nil, err
40 }
41
42 // TODO: de duplicate file paths
43 paths := list.Map(users, func(u *repository.User) string { return u.Path })
44
45 go func(paths []string) {
46 defer close(c)
47 for _, p := range paths {
48 _ = filepath.Walk(p, func(path string, info fs.FileInfo, err error) error {
49 select {
50 case <-ctx.Done():
51 return filepath.SkipAll
52 default:
53 }
54
55 if info == nil {
56 return nil
57 }
58
59 if info.IsDir() && filepath.Base(info.Name())[0] == '.' {
60 return filepath.SkipDir
61 }
62
63 if info.IsDir() {
64 return nil
65 }
66
67 c <- path
68 return nil
69 })
70 }
71 }(paths)
72 return c, nil
73}
74
75func (f *FileScanner) Process(ctx context.Context, path string) error {
76 mimetype := mime.TypeByExtension(filepath.Ext(path))
77 supported := fileop.IsMimeTypeSupported(mimetype)
78 if !supported {
79 return nil
80 }
81
82 hash := fileop.GetHashFromPath(path)
83
84 exists, err := f.mediaRepository.Exists(ctx, hash)
85 if err != nil {
86 return err
87 }
88
89 if exists {
90 return nil
91 }
92
93 return f.mediaRepository.Create(ctx, &repository.CreateMedia{
94 Name: filepath.Base(path),
95 Path: path,
96 PathHash: hash,
97 MIMEType: mimetype,
98 })
99}