From 5f660b309bc695277c67223520499fcc13f3c59f Mon Sep 17 00:00:00 2001 From: Gabriel Arakaki Giovanini Date: Mon, 31 Jul 2023 18:25:13 +0200 Subject: feat: Add album scanner --- pkg/worker/scanner/album_scanner.go | 98 +++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 pkg/worker/scanner/album_scanner.go (limited to 'pkg/worker/scanner/album_scanner.go') diff --git a/pkg/worker/scanner/album_scanner.go b/pkg/worker/scanner/album_scanner.go new file mode 100644 index 0000000..618a184 --- /dev/null +++ b/pkg/worker/scanner/album_scanner.go @@ -0,0 +1,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] + result = append(result, path.Join(subPaths...)) + } + return result +} -- cgit v1.2.3