1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
|
package scanner
import (
"context"
"os"
"path"
"path/filepath"
"strings"
"git.sr.ht/~gabrielgio/img/pkg/database/repository"
"git.sr.ht/~gabrielgio/img/pkg/worker"
)
type (
AlbumScanner struct {
repository repository.MediaRepository
}
)
var _ worker.ListProcessor[*repository.Media] = &AlbumScanner{}
func NewAlbumScanner(repository repository.MediaRepository) *AlbumScanner {
return &AlbumScanner{
repository: repository,
}
}
func (e *AlbumScanner) Query(ctx context.Context) ([]*repository.Media, error) {
return e.repository.ListEmptyAlbums(ctx, &repository.Pagination{
Page: 0,
Size: 100,
})
}
// This process will optmize for file over folder, which means it will assume that there will be
// more file then folder in the overall library.
// So will try to make as cheap as possible to look for fetching many files in a folder
// meaning it will start from checking from left to right in the path since it will assume
// that the path to that point has been registered already, resulting in a single lookup for the media
func (e *AlbumScanner) Process(ctx context.Context, m *repository.Media) error {
// we don't need the name of the file, only its path
filePath, _ := path.Split(m.Path)
parts := strings.Split(filePath, string(os.PathSeparator))
subPaths := FanInwards(parts)
album, err := e.GetAndCreateNestedAlbuns(ctx, subPaths)
if err != nil {
return err
}
return e.repository.CreateAlbumFile(ctx, &repository.CreateAlbumFile{
MediaID: m.ID,
AlbumID: album.ID,
})
}
func (e *AlbumScanner) GetAndCreateNestedAlbuns(ctx context.Context, paths []string) (*repository.Album, error) {
if len(paths) == 1 {
// end of trail, we should create a album without parent
return e.repository.CreateAlbum(ctx, &repository.CreateAlbum{
ParentID: nil,
Name: filepath.Base(paths[0]),
Path: paths[0],
})
}
exists, err := e.repository.ExistsAlbumByAbsolutePath(ctx, paths[0])
if err != nil {
return nil, err
}
if exists {
return e.repository.GetAlbumByAbsolutePath(ctx, paths[0])
}
//album does not exist, create it and get its parent id
a, err := e.GetAndCreateNestedAlbuns(ctx, paths[1:])
if err != nil {
return nil, err
}
return e.repository.CreateAlbum(ctx, &repository.CreateAlbum{
ParentID: &a.ID,
Name: filepath.Base(paths[0]),
Path: paths[0],
})
}
func FanInwards(paths []string) []string {
result := make([]string, 0, len(paths))
for i := (len(paths) - 1); i >= 0; i-- {
subPaths := paths[0:i]
subPaths = append([]string{"/"}, subPaths...)
result = append(result, path.Join(subPaths...))
}
return result
}
|