Add ISO media scan support

This commit is contained in:
ShukeBta
2026-07-16 12:47:31 +08:00
parent 19381eb270
commit cc056077ee
6 changed files with 42 additions and 12 deletions
+5
View File
@@ -43,9 +43,14 @@ var videoExtensions = map[string]struct{}{
".3gp": {},
".mpg": {},
".mpeg": {},
".iso": {},
".strm": {},
}
func mediaExtensionSupportsProbe(ext string) bool {
return ext != ".strm" && ext != ".iso"
}
// ScannerService walks libraries on disk and upserts model.Media rows.
type ScannerService struct {
cfg *config.Config
+3 -3
View File
@@ -76,7 +76,7 @@ func (s *ScannerService) ingestCloudFile(ctx context.Context, lib *model.Library
isNewMedia = !exists
needsTrackProbe = !exists || cloudTrackMetadataMissing(existing)
if exists && existing.LibraryID == lib.ID && existing.SizeBytes == size && existing.STRMURL == expectedSTRMURL && !cloudMetadataNeedsRefresh(existing, localMeta) && !cloudDerivedMetadataNeedsRefresh(existing, m) {
if needsTrackProbe && ext != ".strm" {
if needsTrackProbe && mediaExtensionSupportsProbe(ext) {
s.queueCloudMediaProbeWithBudget(typ, ref, path, probeBudget)
}
res.Skipped++
@@ -90,7 +90,7 @@ func (s *ScannerService) ingestCloudFile(ctx context.Context, lib *model.Library
}
if isNewMedia && writeBatch != nil {
var after func()
if needsTrackProbe && ext != ".strm" {
if needsTrackProbe && mediaExtensionSupportsProbe(ext) {
after = func() {
s.queueCloudMediaProbeWithBudget(typ, ref, path, probeBudget)
}
@@ -103,7 +103,7 @@ func (s *ScannerService) ingestCloudFile(ctx context.Context, lib *model.Library
s.log.Warn("upsert cloud media failed", zap.String("path", path), zap.Error(err))
return
}
if needsTrackProbe && ext != ".strm" {
if needsTrackProbe && mediaExtensionSupportsProbe(ext) {
s.queueCloudMediaProbeWithBudget(typ, ref, path, probeBudget)
}
if isNewMedia {
@@ -63,6 +63,34 @@ func TestIngestPathAddsSingleFile(t *testing.T) {
}
}
func TestScanLibraryImportsISOImage(t *testing.T) {
sc, repos := newScannerTestEnv(t)
root := t.TempDir()
lib := model.Library{Name: "Movies", Path: root, Type: "movie", Enabled: true}
if err := repos.Library.Create(t.Context(), &lib); err != nil {
t.Fatal(err)
}
isoPath := filepath.Join(root, "Movie.Name.2026.iso")
if err := os.WriteFile(isoPath, []byte("iso image"), 0o644); err != nil {
t.Fatal(err)
}
res, err := sc.ScanLibrary(t.Context(), lib.ID)
if err != nil {
t.Fatalf("scan: %v", err)
}
if res.Added != 1 || res.ErrorCount != 0 {
t.Fatalf("scan result = %#v, want one ISO image added without errors", res)
}
var media model.Media
if err := repos.DB.First(&media).Error; err != nil {
t.Fatal(err)
}
if media.Path != isoPath || media.Container != "iso" {
t.Fatalf("ISO media = %#v, want path %q and container iso", media, isoPath)
}
}
func TestScanLibraryReturnsNotFoundForMissingLibrary(t *testing.T) {
sc, _ := newScannerTestEnv(t)
+1 -1
View File
@@ -169,7 +169,7 @@ func (s *ScannerService) buildLocalScanMedia(in localScanMediaInput) *model.Medi
}
func (s *ScannerService) localProbeAfter(path, ext string) func() {
if ext == ".strm" || s.probe == nil {
if !mediaExtensionSupportsProbe(ext) || s.probe == nil {
return nil
}
return func() {
+5 -7
View File
@@ -93,8 +93,8 @@ func TestGenerateSTRMFromTreeSupportsCommonVideoExtensions(t *testing.T) {
if err != nil {
t.Fatal(err)
}
if res.Generated != 5 || len(res.Errors) != 0 {
t.Fatalf("result = %#v, want five common video sources generated and iso ignored", res)
if res.Generated != 6 || len(res.Errors) != 0 {
t.Fatalf("result = %#v, want six common video sources generated", res)
}
for _, name := range []string{
"BluRay.Stream.2026",
@@ -102,15 +102,13 @@ func TestGenerateSTRMFromTreeSupportsCommonVideoExtensions(t *testing.T) {
"DVD.Feature.2026",
"Legacy.Video.2026",
"Web.Legacy.2026",
"Disc.Image.2026",
} {
got := readSTRM(t, filepath.Join(outDir, "Movies", name+".strm"))
if !strings.Contains(got, "/api/cloud/play/openlist?") {
t.Fatalf("%s strm url = %q, want cloud play url", name, got)
}
}
if _, err := os.Stat(filepath.Join(outDir, "Movies", "Disc.Image.2026.strm")); !os.IsNotExist(err) {
t.Fatalf("iso source should stay ignored by tree generator, stat err=%v", err)
}
}
func TestGenerateSTRMFromTreeReportsIgnoredFileLikeRows(t *testing.T) {
@@ -138,8 +136,8 @@ func TestGenerateSTRMFromTreeReportsIgnoredFileLikeRows(t *testing.T) {
if err != nil {
t.Fatal(err)
}
if res.Generated != 2 || res.Ignored != 6 || len(res.IgnoredItems) != 6 {
t.Fatalf("result = %#v, want two generated videos and six ignored sidecars", res)
if res.Generated != 3 || res.Ignored != 5 || len(res.IgnoredItems) != 5 {
t.Fatalf("result = %#v, want three generated videos and five ignored sidecars", res)
}
for _, item := range res.IgnoredItems {
if item == "Show.Name.2026" || item == "电视剧/Show.Name.2026" {
-1
View File
@@ -16,7 +16,6 @@ var strmTreeKnownNonVideoExtensions = map[string]struct{}{
".bmp": {},
".gif": {},
".idx": {},
".iso": {},
".jpeg": {},
".jpg": {},
".nfo": {},