summaryrefslogtreecommitdiff
path: root/internal/scanner
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-05-09 11:11:49 +0300
committerPaul Buetow <paul@buetow.org>2026-05-09 11:11:49 +0300
commit8c32cd117abe79f4ee6cff3a950ffc35c95faeff (patch)
tree5b63a4789351da4f2d9c1cd2e7007f67d43b3371 /internal/scanner
parent59c8870061465142306e7a6e5d3fcb344686cfe9 (diff)
Refine media browsing and set covers
Diffstat (limited to 'internal/scanner')
-rw-r--r--internal/scanner/scanner.go11
-rw-r--r--internal/scanner/scanner_test.go52
2 files changed, 62 insertions, 1 deletions
diff --git a/internal/scanner/scanner.go b/internal/scanner/scanner.go
index 92bc6c3..dc5f34f 100644
--- a/internal/scanner/scanner.go
+++ b/internal/scanner/scanner.go
@@ -116,6 +116,12 @@ func (s *FSScanner) ensureSet(ctx context.Context, root, setPath string) (int64,
for i := range sets {
if sets[i].RootPath == relRoot {
+ if isPodcastRoot(relRoot) && !sets[i].IsPodcast {
+ sets[i].IsPodcast = true
+ if err := s.store.UpdateSet(ctx, &sets[i]); err != nil {
+ return 0, "", fmt.Errorf("update podcast set %q: %w", setName, err)
+ }
+ }
return sets[i].ID, setName, nil
}
}
@@ -123,6 +129,7 @@ func (s *FSScanner) ensureSet(ctx context.Context, root, setPath string) (int64,
newSet := &model.Set{
Name: setName,
RootPath: relRoot,
+ IsPodcast: isPodcastRoot(relRoot),
CreatedAt: s.clock.Now(),
}
id, err := s.store.CreateSet(ctx, newSet)
@@ -132,6 +139,10 @@ func (s *FSScanner) ensureSet(ctx context.Context, root, setPath string) (int64,
return id, setName, nil
}
+func isPodcastRoot(rootPath string) bool {
+ return strings.EqualFold(filepath.ToSlash(rootPath), "podcast")
+}
+
// loadExistingMedia builds a lookup map of existing media keyed by relPath.
func (s *FSScanner) loadExistingMedia(ctx context.Context, setID int64, setName string) (map[string]model.Media, error) {
existing := make(map[string]model.Media)
diff --git a/internal/scanner/scanner_test.go b/internal/scanner/scanner_test.go
index 3a77f72..ad6ddd7 100644
--- a/internal/scanner/scanner_test.go
+++ b/internal/scanner/scanner_test.go
@@ -268,6 +268,57 @@ func TestFSScanner_Scan(t *testing.T) {
}
})
+ t.Run("scans all top-level dirs and marks canonical podcast root", func(t *testing.T) {
+ mfs := &mockFS{
+ entries: map[string][]os.DirEntry{
+ "/media": {
+ mockDirEntry{name: "qa-stable-podcast-1", isDir: true},
+ mockDirEntry{name: "podcast", isDir: true},
+ },
+ },
+ fileInfos: map[string]os.FileInfo{
+ "/media/podcast/feed/episode.mp3": mockFileInfo{name: "episode.mp3", size: 500},
+ },
+ walkList: []walkEntry{
+ {path: "/media/podcast", isDir: true},
+ {path: "/media/podcast/feed", isDir: true},
+ {path: "/media/podcast/feed/episode.mp3", isDir: false},
+ },
+ }
+ store := repository.NewMockStore()
+ store.SetRepo.ListSetsFunc = func(_ context.Context) ([]model.Set, error) { return nil, nil }
+ var createdSets []model.Set
+ store.SetRepo.CreateSetFunc = func(_ context.Context, set *model.Set) (int64, error) {
+ createdSets = append(createdSets, *set)
+ return int64(len(createdSets)), nil
+ }
+ store.MediaRepo.ListMediaFunc = func(_ context.Context, filter repository.MediaFilter) ([]model.Media, error) {
+ return nil, nil
+ }
+ store.MediaRepo.CreateMediaFunc = func(_ context.Context, m *model.Media) (int64, error) {
+ return 1, nil
+ }
+ prober := &probe.MockProber{
+ ProbeFunc: func(_ context.Context, path string) (*model.Metadata, error) {
+ return &model.Metadata{Duration: 180, Codec: "mp3", Bitrate: 256}, nil
+ },
+ }
+
+ s := newTestScanner(store, prober, &thumb.MockGenerator{}, clk, mfs)
+ if err := s.Scan(ctx, "/media", nil); err != nil {
+ t.Fatalf("unexpected error: %v", err)
+ }
+ if len(createdSets) != 2 {
+ t.Fatalf("expected both top-level dirs to be created, got %+v", createdSets)
+ }
+ if createdSets[0].RootPath != "qa-stable-podcast-1" {
+ t.Fatalf("expected qa-stable-podcast-1 root path, got %+v", createdSets[0])
+ }
+ if createdSets[1].RootPath != "podcast" || !createdSets[1].IsPodcast {
+ t.Fatalf("expected podcast root path marked as podcast, got %+v", createdSets[1])
+ }
+ })
+
t.Run("nested directories", func(t *testing.T) {
mfs := &mockFS{
entries: map[string][]os.DirEntry{
@@ -501,4 +552,3 @@ func TestFSScanner_collectFiles(t *testing.T) {
}
})
}
-