From eb79cecc44628d3e24b2196e1d680f2b1ba15f97 Mon Sep 17 00:00:00 2001 From: sentriz Date: Tue, 2 Jan 2024 23:06:32 +0000 Subject: [PATCH] fix(scanner): gracefully handle multi value tag delim splits with adjacent delimiters closes #448 Co-authored-by: Chris Hayes --- scanner/scanner.go | 18 +++++++++++------- scanner/scanner_test.go | 16 ++++++++++++++++ server/ctrlsubsonic/handlers_common.go | 6 +++++- 3 files changed, 32 insertions(+), 8 deletions(-) diff --git a/scanner/scanner.go b/scanner/scanner.go index 7296a5ed..aefa4c11 100644 --- a/scanner/scanner.go +++ b/scanner/scanner.go @@ -9,6 +9,7 @@ import ( "os" "path/filepath" "regexp" + "slices" "sort" "strconv" "strings" @@ -319,7 +320,7 @@ func (s *Scanner) populateTrackAndArtists(tx *db.DB, st *State, i int, album *db return fmt.Errorf("%w: %w", err, ErrReadingTags) } - genreNames := parseMulti(trags, s.multiValueSettings[Genre], tagcommon.MustGenres, tagcommon.MustGenre) + genreNames := ParseMulti(s.multiValueSettings[Genre], tagcommon.MustGenres(trags), tagcommon.MustGenre(trags)) genreIDs, err := populateGenres(tx, genreNames) if err != nil { return fmt.Errorf("populate genres: %w", err) @@ -331,7 +332,7 @@ func (s *Scanner) populateTrackAndArtists(tx *db.DB, st *State, i int, album *db return fmt.Errorf("delete artist appearances: %w", err) } - albumArtistNames := parseMulti(trags, s.multiValueSettings[AlbumArtist], tagcommon.MustAlbumArtists, tagcommon.MustAlbumArtist) + albumArtistNames := ParseMulti(s.multiValueSettings[AlbumArtist], tagcommon.MustAlbumArtists(trags), tagcommon.MustAlbumArtist(trags)) var albumArtistIDs []int for _, albumArtistName := range albumArtistNames { albumArtist, err := populateArtist(tx, albumArtistName) @@ -364,7 +365,7 @@ func (s *Scanner) populateTrackAndArtists(tx *db.DB, st *State, i int, album *db return fmt.Errorf("populate track genres: %w", err) } - trackArtistNames := parseMulti(trags, s.multiValueSettings[Artist], tagcommon.MustArtists, tagcommon.MustArtist) + trackArtistNames := ParseMulti(s.multiValueSettings[Artist], tagcommon.MustArtists(trags), tagcommon.MustArtist(trags)) var trackArtistIDs []int for _, trackArtistName := range trackArtistNames { trackArtist, err := populateArtist(tx, trackArtistName) @@ -704,19 +705,22 @@ type MultiValueSetting struct { Delim string } -func parseMulti(parser tagcommon.Info, setting MultiValueSetting, getMulti func(tagcommon.Info) []string, get func(tagcommon.Info) string) []string { +func ParseMulti(setting MultiValueSetting, values []string, value string) []string { var parts []string switch setting.Mode { case Multi: - parts = getMulti(parser) + parts = values case Delim: - parts = strings.Split(get(parser), setting.Delim) + parts = strings.Split(value, setting.Delim) default: - parts = []string{get(parser)} + parts = []string{value} } for i := range parts { parts[i] = strings.TrimSpace(parts[i]) } + parts = slices.DeleteFunc(parts, func(s string) bool { + return s == "" + }) return parts } diff --git a/scanner/scanner_test.go b/scanner/scanner_test.go index c2b281bc..77f4b1c6 100644 --- a/scanner/scanner_test.go +++ b/scanner/scanner_test.go @@ -810,3 +810,19 @@ func TestPrefixOverlap(t *testing.T) { require.NoError(t, m.DB().Model(db.Album{}).Where("root_dir LIKE ?", `%/tagged`).Count(&tagged).Error) require.Greater(t, tagged, 1) } + +// https://github.com/sentriz/gonic/pull/448 +func TestParseMultiDoubleDelim(t *testing.T) { + t.Parallel() + + setting := scanner.MultiValueSetting{ + Mode: scanner.Delim, + Delim: `/`, + } + + values := scanner.ParseMulti(setting, nil, `DON'T//BE//⚜⚜⚜`) + require.Len(t, values, 3) + require.Equal(t, `DON'T`, values[0]) + require.Equal(t, `BE`, values[1]) + require.Equal(t, `⚜⚜⚜`, values[2]) +} diff --git a/server/ctrlsubsonic/handlers_common.go b/server/ctrlsubsonic/handlers_common.go index ca9adb65..ac1ef70b 100644 --- a/server/ctrlsubsonic/handlers_common.go +++ b/server/ctrlsubsonic/handlers_common.go @@ -518,7 +518,11 @@ func getMusicFolder(musicPaths []MusicPath, p params.Params) string { } func lowerUDecOrHash(in string) string { - lower := unicode.ToLower(rune(in[0])) + inRunes := []rune(in) + if len(inRunes) == 0 { + return "" + } + lower := unicode.ToLower(inRunes[0]) if !unicode.IsLetter(lower) { return "#" }