diff --git a/persistence/mediafile_repository.go b/persistence/mediafile_repository.go index ffda9c17b..d01421052 100644 --- a/persistence/mediafile_repository.go +++ b/persistence/mediafile_repository.go @@ -5,6 +5,7 @@ import ( "fmt" "os" "path/filepath" + "strings" "unicode/utf8" . "github.com/Masterminds/squirrel" @@ -94,9 +95,23 @@ func (r mediaFileRepository) FindByPath(path string) (*model.MediaFile, error) { return &res[0], nil } +func cleanPath(path string) string { + path = filepath.Clean(path) + if !strings.HasSuffix(path, string(os.PathSeparator)) { + path = path + string(os.PathSeparator) + } + return path +} + +func pathStartsWith(path string) Eq { + substr := fmt.Sprintf("substr(path, 1, %d)", utf8.RuneCountInString(path)) + return Eq{substr: path} +} + // FindAllByPath only return mediafiles that are direct children of requested path func (r mediaFileRepository) FindAllByPath(path string) (model.MediaFiles, error) { // Query by path based on https://stackoverflow.com/a/13911906/653632 + path = cleanPath(path) pathLen := utf8.RuneCountInString(path) sel0 := r.selectMediaFile().Columns(fmt.Sprintf("substr(path, %d) AS item", pathLen+2)). Where(pathStartsWith(path)) @@ -108,24 +123,20 @@ func (r mediaFileRepository) FindAllByPath(path string) (model.MediaFiles, error return res, err } -func pathStartsWith(path string) Eq { - cleanPath := filepath.Clean(path) - substr := fmt.Sprintf("substr(path, 1, %d)", utf8.RuneCountInString(cleanPath)) - return Eq{substr: cleanPath} -} - // FindPathsRecursively returns a list of all subfolders of basePath, recursively func (r mediaFileRepository) FindPathsRecursively(basePath string) ([]string, error) { + path := cleanPath(basePath) // Query based on https://stackoverflow.com/a/38330814/653632 sel := r.newSelect().Columns(fmt.Sprintf("distinct rtrim(path, replace(path, '%s', ''))", string(os.PathSeparator))). - Where(pathStartsWith(basePath)) + Where(pathStartsWith(path)) var res []string err := r.queryAll(sel, &res) return res, err } func (r mediaFileRepository) deleteNotInPath(basePath string) error { - sel := Delete(r.tableName).Where(NotEq(pathStartsWith(basePath))) + path := cleanPath(basePath) + sel := Delete(r.tableName).Where(NotEq(pathStartsWith(path))) c, err := r.executeSQL(sel) if err == nil { if c > 0 { @@ -156,8 +167,8 @@ func (r mediaFileRepository) Delete(id string) error { } // DeleteByPath delete from the DB all mediafiles that are direct children of path -func (r mediaFileRepository) DeleteByPath(path string) (int64, error) { - path = filepath.Clean(path) +func (r mediaFileRepository) DeleteByPath(basePath string) (int64, error) { + path := cleanPath(basePath) pathLen := utf8.RuneCountInString(path) del := Delete(r.tableName). Where(And{pathStartsWith(path), diff --git a/persistence/mediafile_repository_test.go b/persistence/mediafile_repository_test.go index d08c0d1d0..4b42ad3b2 100644 --- a/persistence/mediafile_repository_test.go +++ b/persistence/mediafile_repository_test.go @@ -137,6 +137,19 @@ var _ = Describe("MediaRepository", func() { Expect(mr.FindAllByPath(P("/Legião Urbana"))).To(HaveLen(0)) }) + It("only deletes tracks that match exact path", func() { + id1 := "6021" + Expect(mr.Put(&model.MediaFile{ID: id1, Path: P("/music/overlap/Ella Fitzgerald/" + id1 + ".mp3")})).To(BeNil()) + id2 := "6022" + Expect(mr.Put(&model.MediaFile{ID: id2, Path: P("/music/overlap/Ella Fitzgerald/" + id2 + ".mp3")})).To(BeNil()) + id3 := "6023" + Expect(mr.Put(&model.MediaFile{ID: id3, Path: P("/music/overlap/Ella Fitzgerald & Louis Armstrong - They Can't Take That Away From Me.mp3")})).To(BeNil()) + + Expect(mr.FindAllByPath(P("/music/overlap/Ella Fitzgerald"))).To(HaveLen(2)) + Expect(mr.DeleteByPath(P("/music/overlap/Ella Fitzgerald"))).To(Equal(int64(2))) + Expect(mr.FindAllByPath(P("/music/overlap"))).To(HaveLen(1)) + }) + Context("Annotations", func() { It("increments play count when the tracks does not have annotations", func() { id := "incplay.firsttime"