mirror of
https://github.com/navidrome/navidrome.git
synced 2026-04-28 03:19:38 +00:00
fix(playlists): better M3U paths matching across different UTF representations (#4890)
Some checks are pending
Pipeline: Test, Lint, Build / Lint i18n files (push) Waiting to run
Pipeline: Test, Lint, Build / Check Docker configuration (push) Waiting to run
Pipeline: Test, Lint, Build / Get version info (push) Waiting to run
Pipeline: Test, Lint, Build / Lint Go code (push) Waiting to run
Pipeline: Test, Lint, Build / Test Go code (push) Waiting to run
Pipeline: Test, Lint, Build / Test JS code (push) Waiting to run
Pipeline: Test, Lint, Build / Build (push) Blocked by required conditions
Pipeline: Test, Lint, Build / Build-1 (push) Blocked by required conditions
Pipeline: Test, Lint, Build / Build-2 (push) Blocked by required conditions
Pipeline: Test, Lint, Build / Build-3 (push) Blocked by required conditions
Pipeline: Test, Lint, Build / Build-4 (push) Blocked by required conditions
Pipeline: Test, Lint, Build / Build-5 (push) Blocked by required conditions
Pipeline: Test, Lint, Build / Build-6 (push) Blocked by required conditions
Pipeline: Test, Lint, Build / Build-7 (push) Blocked by required conditions
Pipeline: Test, Lint, Build / Build-8 (push) Blocked by required conditions
Pipeline: Test, Lint, Build / Build-9 (push) Blocked by required conditions
Pipeline: Test, Lint, Build / Push to GHCR (push) Blocked by required conditions
Pipeline: Test, Lint, Build / Push to Docker Hub (push) Blocked by required conditions
Pipeline: Test, Lint, Build / Cleanup digest artifacts (push) Blocked by required conditions
Pipeline: Test, Lint, Build / Build Windows installers (push) Blocked by required conditions
Pipeline: Test, Lint, Build / Package/Release (push) Blocked by required conditions
Pipeline: Test, Lint, Build / Upload Linux PKG (push) Blocked by required conditions
Some checks are pending
Pipeline: Test, Lint, Build / Lint i18n files (push) Waiting to run
Pipeline: Test, Lint, Build / Check Docker configuration (push) Waiting to run
Pipeline: Test, Lint, Build / Get version info (push) Waiting to run
Pipeline: Test, Lint, Build / Lint Go code (push) Waiting to run
Pipeline: Test, Lint, Build / Test Go code (push) Waiting to run
Pipeline: Test, Lint, Build / Test JS code (push) Waiting to run
Pipeline: Test, Lint, Build / Build (push) Blocked by required conditions
Pipeline: Test, Lint, Build / Build-1 (push) Blocked by required conditions
Pipeline: Test, Lint, Build / Build-2 (push) Blocked by required conditions
Pipeline: Test, Lint, Build / Build-3 (push) Blocked by required conditions
Pipeline: Test, Lint, Build / Build-4 (push) Blocked by required conditions
Pipeline: Test, Lint, Build / Build-5 (push) Blocked by required conditions
Pipeline: Test, Lint, Build / Build-6 (push) Blocked by required conditions
Pipeline: Test, Lint, Build / Build-7 (push) Blocked by required conditions
Pipeline: Test, Lint, Build / Build-8 (push) Blocked by required conditions
Pipeline: Test, Lint, Build / Build-9 (push) Blocked by required conditions
Pipeline: Test, Lint, Build / Push to GHCR (push) Blocked by required conditions
Pipeline: Test, Lint, Build / Push to Docker Hub (push) Blocked by required conditions
Pipeline: Test, Lint, Build / Cleanup digest artifacts (push) Blocked by required conditions
Pipeline: Test, Lint, Build / Build Windows installers (push) Blocked by required conditions
Pipeline: Test, Lint, Build / Package/Release (push) Blocked by required conditions
Pipeline: Test, Lint, Build / Upload Linux PKG (push) Blocked by required conditions
* fix: improve playlist path normalization for cross-platform compatibility Signed-off-by: Deluan <deluan@navidrome.org> * fix: log normalized path when playlist path is not found Signed-off-by: Deluan <deluan@navidrome.org> * test: enhance Unicode normalization tests for playlist paths Signed-off-by: Deluan <deluan@navidrome.org> * fix: enhance playlist path normalization for cross-platform compatibility See https://github.com/navidrome/navidrome/pull/4789#issuecomment-3645724780 Signed-off-by: Deluan <deluan@navidrome.org> * fix: improve playlist path normalization to handle fullwidth characters and enhance cross-platform compatibility Signed-off-by: Deluan <deluan@navidrome.org> * formatting Signed-off-by: Deluan <deluan@navidrome.org> * fix: adjust chunk size for M3U parsing to optimize SQLite expression tree depth Signed-off-by: Deluan <deluan@navidrome.org> --------- Signed-off-by: Deluan <deluan@navidrome.org>
This commit is contained in:
parent
c6c1c16923
commit
b455546fdf
3 changed files with 275 additions and 34 deletions
|
|
@ -561,4 +561,92 @@ var _ = Describe("MediaRepository", func() {
|
|||
})
|
||||
})
|
||||
})
|
||||
|
||||
Describe("FindByPaths", func() {
|
||||
// Test fixtures for Unicode and case-sensitivity tests
|
||||
var testFiles []model.MediaFile
|
||||
|
||||
BeforeEach(func() {
|
||||
testFiles = []model.MediaFile{
|
||||
{ID: "findpath-1", LibraryID: 1, Path: "artist/Album/track.mp3", Title: "Track"},
|
||||
{ID: "findpath-2", LibraryID: 1, Path: "artist/Album/UPPER.mp3", Title: "Upper"},
|
||||
// Fullwidth uppercase: ACROSS (U+FF21 U+FF23 U+FF32 U+FF2F U+FF33 U+FF33)
|
||||
{ID: "findpath-3", LibraryID: 1, Path: "plex/02 - ACROSS.flac", Title: "Fullwidth"},
|
||||
// French diacritic: è (U+00E8, can decompose to e + combining grave)
|
||||
{ID: "findpath-4", LibraryID: 1, Path: "artist/Michèle/song.mp3", Title: "French"},
|
||||
}
|
||||
for _, mf := range testFiles {
|
||||
Expect(mr.Put(&mf)).To(Succeed())
|
||||
}
|
||||
})
|
||||
|
||||
AfterEach(func() {
|
||||
for _, mf := range testFiles {
|
||||
_ = mr.Delete(mf.ID)
|
||||
}
|
||||
})
|
||||
|
||||
It("finds files by exact path", func() {
|
||||
results, err := mr.FindByPaths([]string{"1:artist/Album/track.mp3"})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(results).To(HaveLen(1))
|
||||
Expect(results[0].ID).To(Equal("findpath-1"))
|
||||
})
|
||||
|
||||
It("finds files case-insensitively for ASCII characters (NOCASE)", func() {
|
||||
// SQLite's COLLATE NOCASE handles ASCII case-insensitivity
|
||||
results, err := mr.FindByPaths([]string{"1:ARTIST/ALBUM/TRACK.MP3"})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(results).To(HaveLen(1))
|
||||
Expect(results[0].ID).To(Equal("findpath-1"))
|
||||
})
|
||||
|
||||
It("finds fullwidth characters only with exact case match (SQLite NOCASE limitation)", func() {
|
||||
// SQLite's NOCASE does NOT handle fullwidth uppercase/lowercase equivalence
|
||||
// The DB has fullwidth uppercase ACROSS, searching with exact match should work
|
||||
results, err := mr.FindByPaths([]string{"1:plex/02 - ACROSS.flac"})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(results).To(HaveLen(1))
|
||||
Expect(results[0].ID).To(Equal("findpath-3"))
|
||||
|
||||
// Searching with fullwidth lowercase across should NOT match
|
||||
// (this is the SQLite limitation that requires exact matching for non-ASCII)
|
||||
results, err = mr.FindByPaths([]string{"1:plex/02 - across.flac"})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(results).To(BeEmpty())
|
||||
})
|
||||
|
||||
It("returns multiple files when querying multiple paths", func() {
|
||||
results, err := mr.FindByPaths([]string{
|
||||
"1:artist/Album/track.mp3",
|
||||
"1:artist/Album/UPPER.mp3",
|
||||
})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(results).To(HaveLen(2))
|
||||
})
|
||||
|
||||
It("returns empty slice for non-existent paths", func() {
|
||||
results, err := mr.FindByPaths([]string{"1:nonexistent/path.mp3"})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(results).To(BeEmpty())
|
||||
})
|
||||
|
||||
It("returns empty slice for empty input", func() {
|
||||
results, err := mr.FindByPaths([]string{})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(results).To(BeEmpty())
|
||||
})
|
||||
|
||||
It("handles library-qualified paths correctly", func() {
|
||||
// Library 1 should find the file
|
||||
results, err := mr.FindByPaths([]string{"1:artist/Album/track.mp3"})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(results).To(HaveLen(1))
|
||||
|
||||
// Library 2 should NOT find it (file is in library 1)
|
||||
results, err = mr.FindByPaths([]string{"2:artist/Album/track.mp3"})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(results).To(BeEmpty())
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue