package backend import ( "regexp" "strings" "sync" ) // SoundtrackData holds precomputed search data for a soundtrack type SoundtrackData struct { Original string Lowercase string Cleaned string } var ( searchCache []SoundtrackData searchCacheMutex sync.Mutex searchRegexCache = make(map[string]*regexp.Regexp) searchRegexCacheMutex sync.Mutex ) // GetSearchCache returns the precomputed search cache, initializing it if needed func GetSearchCache() []SoundtrackData { searchCacheMutex.Lock() defer searchCacheMutex.Unlock() if len(searchCache) == 0 { loadSearchCache() } return searchCache } // ReloadSearchCache clears and reloads the search cache. // This should be called after a sync operation to ensure search results are up to date. func ReloadSearchCache() { searchCacheMutex.Lock() defer searchCacheMutex.Unlock() searchCache = nil loadSearchCache() } // loadSearchCache loads the soundtrack data into the cache func loadSearchCache() { soundtracks := GetAllSoundtracks() searchCache = make([]SoundtrackData, len(soundtracks)) for i, soundtrack := range soundtracks { cleaned := cleanSearchTerm(soundtrack) lowercase := strings.ToLower(soundtrack) searchCache[i] = SoundtrackData{ Original: soundtrack, Lowercase: lowercase, Cleaned: cleaned, } } } // CleanSearchTermForMatch cleans a search term for better matching func CleanSearchTermForMatch(term string) string { term = strings.ReplaceAll(term, " ", "") term = strings.ReplaceAll(term, "é", "e") term = strings.ReplaceAll(term, "+", "plus") term = strings.ReplaceAll(term, "&", "and") term = strings.ReplaceAll(term, "'n", "and") return strings.ToLower(term) } // cleanSearchTerm cleans a search term for better matching (internal) func cleanSearchTerm(term string) string { return CleanSearchTermForMatch(term) } // MatchRegexCached checks if a search term matches using cached compiled regex func MatchRegexCached(searchTerm string, soundtrackName string) bool { if searchTerm == "" { return true } // Check cache first searchRegexCacheMutex.Lock() re, exists := searchRegexCache[searchTerm] if !exists { re = compileSearchRegex(searchTerm) searchRegexCache[searchTerm] = re } searchRegexCacheMutex.Unlock() return re.MatchString(soundtrackName) } // compileSearchRegex compiles a search term into a regex pattern func compileSearchRegex(searchTerm string) *regexp.Regexp { regText := ".*" for _, letter := range searchTerm { regText += string(letter) + ".*" } re, _ := regexp.Compile(regText) return re }