package common import ( "errors" "strings" ) func Unify(s string) string { s = strings.TrimSpace(s) s = strings.ToLower(s) for strings.Contains(s, " ") { s = strings.ReplaceAll(s, " ", " ") } return s } type Query struct { Search string Artist string Album string Song string } const emptyChar = ' ' const songChar = 's' const albumChar = 'r' const artistChar = 'a' func NewQuery(search string) (Query, error) { search = strings.TrimSpace(search) query := Query{ Search: search, } if search == "" { return query, errors.New("search should not be empty") } parsed := make(map[rune]string) indexChar := emptyChar nextIsIndex := false ignoreNextIfSpace := false for _, char := range search { // figuring out when the next char is an index char if char == '#' { // escape # => asserts previous char was also # if nextIsIndex { nextIsIndex = false parsed[indexChar] = parsed[indexChar] + "#" continue } nextIsIndex = true continue } // setting an index char if nextIsIndex { if char != songChar && char != albumChar && char != artistChar { return query, errors.New("the char after # has to be " + string(songChar) + ", " + string(albumChar) + " or " + string(artistChar) + " if it isn't escaped with another #") } if _, ok := parsed[char]; ok { return query, errors.New("you can use #" + string(char) + " only once") } indexChar = char nextIsIndex = false ignoreNextIfSpace = true parsed[char] = "" continue } if ignoreNextIfSpace { ignoreNextIfSpace = false if char == ' ' { continue } } parsed[indexChar] = parsed[indexChar] + string(char) } if nextIsIndex { return query, errors.New("there cant be an unescaped # at the end, it has to be escaped with another #") } if _, ok := parsed[emptyChar]; ok { // no other index char should be used e := errors.New("if you use advanced search with # you cant put anything before the first #") if _, ok := parsed[songChar]; ok { return query, e } if _, ok := parsed[albumChar]; ok { return query, e } if _, ok := parsed[artistChar]; ok { return query, e } query.Search = parsed[emptyChar] } else { query.Song = strings.TrimSpace(parsed[songChar]) query.Album = strings.TrimSpace(parsed[albumChar]) query.Artist = strings.TrimSpace(parsed[artistChar]) elements := []string{} if query.Song != "" { elements = append(elements, query.Song) } if query.Album != "" && !(query.Song != "" && query.Album != "") { elements = append(elements, query.Album) } if query.Artist != "" { elements = append(elements, query.Artist) } query.Search = strings.Join(elements, " - ") } return query, nil }