diff --git a/core/playlists.go b/core/playlists.go index a29dfa247..81393bc94 100644 --- a/core/playlists.go +++ b/core/playlists.go @@ -9,6 +9,7 @@ import ( "net/url" "os" "path/filepath" + "regexp" "strings" "time" @@ -228,31 +229,39 @@ func (s *playlists) normalizePaths(ctx context.Context, pls *model.Playlist, fol if err != nil { return nil, err } - // Normalize paths to be relative to the library root. Search for roots in any library - var res []string + + // Create regex patterns for each library path + patterns := make([]string, len(libs)) + for i, lib := range libs { + cleanPath := filepath.Clean(lib.Path) + escapedPath := regexp.QuoteMeta(cleanPath) + patterns[i] = fmt.Sprintf("^%s(?:/|$)", escapedPath) + } + // Combine all patterns into a single regex + combinedPattern := strings.Join(patterns, "|") + libRegex := regexp.MustCompile(combinedPattern) + + res := make([]string, 0, len(lines)) for idx, line := range lines { var libPath string var filePath string + if folder != nil && !filepath.IsAbs(line) { libPath = folder.LibraryPath filePath = filepath.Join(folder.AbsolutePath(), line) } else { - for _, lib := range libs { - if strings.HasPrefix(line, lib.Path) { - libPath = lib.Path - filePath = line - break - } + cleanLine := filepath.Clean(line) + if libPath = libRegex.FindString(cleanLine); libPath != "" { + filePath = cleanLine } } + if libPath != "" { - var err error - filePath, err = filepath.Rel(libPath, filePath) - if err != nil { + if rel, err := filepath.Rel(libPath, filePath); err == nil { + res = append(res, rel) + } else { log.Trace(ctx, "Error getting relative path", "playlist", pls.Name, "path", line, "folder", folder, err) - continue } - res = append(res, filePath) } else { log.Warn(ctx, "Path in playlist not found in any library", "path", line, "line", idx) } diff --git a/core/playlists_test.go b/core/playlists_test.go index 7241dd1b5..7a85c6c70 100644 --- a/core/playlists_test.go +++ b/core/playlists_test.go @@ -56,10 +56,9 @@ var _ = Describe("Playlists", func() { pls, err := ps.ImportFile(ctx, folder, "pls1.m3u") Expect(err).ToNot(HaveOccurred()) Expect(pls.OwnerID).To(Equal("123")) - Expect(pls.Tracks).To(HaveLen(3)) + Expect(pls.Tracks).To(HaveLen(2)) Expect(pls.Tracks[0].Path).To(Equal("tests/fixtures/playlists/test.mp3")) Expect(pls.Tracks[1].Path).To(Equal("tests/fixtures/playlists/test.ogg")) - Expect(pls.Tracks[2].Path).To(Equal("tests/fixtures/01 Invisible (RED) Edit Version.mp3")) Expect(mockPlsRepo.last).To(Equal(pls)) }) diff --git a/tests/fixtures/playlists/pls1.m3u b/tests/fixtures/playlists/pls1.m3u index d8f30e943..98e6d9675 100644 --- a/tests/fixtures/playlists/pls1.m3u +++ b/tests/fixtures/playlists/pls1.m3u @@ -1,3 +1,2 @@ test.mp3 -test.ogg -file:///tests/fixtures/01%20Invisible%20(RED)%20Edit%20Version.mp3 \ No newline at end of file +test.ogg \ No newline at end of file diff --git a/tests/test_helpers.go b/tests/test_helpers.go index e1d29622a..1251c90cd 100644 --- a/tests/test_helpers.go +++ b/tests/test_helpers.go @@ -2,7 +2,6 @@ package tests import ( "context" - "io/fs" "os" "path/filepath" @@ -18,7 +17,7 @@ func TempFileName(t testingT, prefix, suffix string) string { return filepath.Join(t.TempDir(), prefix+id.NewRandom()+suffix) } -func TempFile(t testingT, prefix, suffix string) (fs.File, string, error) { +func TempFile(t testingT, prefix, suffix string) (*os.File, string, error) { name := TempFileName(t, prefix, suffix) f, err := os.Create(name) return f, name, err diff --git a/utils/slice/slice_test.go b/utils/slice/slice_test.go index 40569c07b..c6d4be1e0 100644 --- a/utils/slice/slice_test.go +++ b/utils/slice/slice_test.go @@ -140,7 +140,7 @@ var _ = Describe("Slice Utils", func() { Expect(count).To(Equal(expected)) }, Entry("returns empty slice for an empty input", "tests/fixtures/empty.txt", 0), - Entry("returns the lines of a file", "tests/fixtures/playlists/pls1.m3u", 3), + Entry("returns the lines of a file", "tests/fixtures/playlists/pls1.m3u", 2), Entry("returns empty if file does not exist", "tests/fixtures/NON-EXISTENT", 0), )