113 lines
2.3 KiB
Go

package search
import (
"sort"
"strings"
"github.com/animenotifier/notify.moe/arn"
"github.com/animenotifier/notify.moe/arn/stringutils"
)
// Characters searches all characters.
func Characters(originalTerm string, maxLength int) []*arn.Character {
if maxLength == 0 {
return nil
}
term := strings.ToLower(stringutils.RemoveSpecialCharacters(originalTerm))
termHasUnicode := stringutils.ContainsUnicodeLetters(term)
results := make([]*Result, 0, maxLength)
for character := range arn.StreamCharacters() {
if character.ID == originalTerm {
return []*arn.Character{character}
}
if character.Image.Extension == "" {
continue
}
// Canonical
text := strings.ToLower(stringutils.RemoveSpecialCharacters(character.Name.Canonical))
if text == term {
results = append(results, &Result{
obj: character,
similarity: float64(20 + len(character.Likes)),
})
continue
}
spaceCount := 0
start := 0
found := false
for i := 0; i <= len(text); i++ {
if i == len(text) || text[i] == ' ' {
part := text[start:i]
if part == term {
results = append(results, &Result{
obj: character,
similarity: float64(10 - spaceCount*5 + len(character.Likes)),
})
found = true
break
}
start = i + 1
spaceCount++
}
}
if found {
continue
}
// Japanese
if termHasUnicode {
if strings.Contains(character.Name.Japanese, term) {
results = append(results, &Result{
obj: character,
similarity: float64(len(character.Likes)),
})
continue
}
}
}
// Sort
sort.Slice(results, func(i, j int) bool {
similarityA := results[i].similarity
similarityB := results[j].similarity
if similarityA == similarityB {
characterA := results[i].obj.(*arn.Character)
characterB := results[j].obj.(*arn.Character)
if characterA.Name.Canonical == characterB.Name.Canonical {
return characterA.ID < characterB.ID
}
return characterA.Name.Canonical < characterB.Name.Canonical
}
return similarityA > similarityB
})
// Limit
if len(results) >= maxLength {
results = results[:maxLength]
}
// Final list
final := make([]*arn.Character, len(results))
for i, result := range results {
final[i] = result.obj.(*arn.Character)
}
return final
}