lens @ 7a414da9a802d5eeee911b3536790a061e1d7503

 1package worker
 2
 3import (
 4	"context"
 5	"crypto/md5"
 6	"encoding/hex"
 7	"io/fs"
 8	"mime"
 9	"path/filepath"
10	"strings"
11
12	"git.sr.ht/~gabrielgio/img/pkg/database/repository"
13)
14
15type (
16	FileScanner struct {
17		root       string
18		repository repository.MediaRepository
19	}
20)
21
22var _ ChanProcessor[string] = &FileScanner{}
23
24func NewFileScanner(root string, repository repository.MediaRepository) *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 == nil {
43				return nil
44			}
45
46			if info.IsDir() && filepath.Base(info.Name())[0] == '.' {
47				return filepath.SkipDir
48			}
49
50			if info.IsDir() {
51				return nil
52			}
53
54			c <- path
55			return nil
56		})
57	}()
58	return c, nil
59}
60
61func (f *FileScanner) Process(ctx context.Context, path string) error {
62	m := mime.TypeByExtension(filepath.Ext(path))
63	if !strings.HasPrefix(m, "video") && !strings.HasPrefix(m, "image") {
64		return nil
65	}
66
67	hash := md5.Sum([]byte(path))
68	str := hex.EncodeToString(hash[:])
69	name := filepath.Base(path)
70
71	exists, errResp := f.repository.Exists(ctx, str)
72	if errResp != nil {
73		return errResp
74	}
75
76	if exists {
77		return nil
78	}
79
80	return f.repository.Create(ctx, &repository.CreateMedia{
81		Name:     name,
82		Path:     path,
83		PathHash: str,
84		MIMEType: m,
85	})
86}