Files
silo-server/internal/literaryworks/normalize.go
e084cdd1d6 Add unified literary works for ebooks and audiobooks (#107)
* docs: add literary works design and plan

* feat(literary): add work link schema

* feat(literary): add work domain primitives

* feat(literary): persist work links

* feat(literary): score work matches

* feat(catalog): include literary work summary on item detail

* feat(literary): expose work detail API

* feat(literary): assemble work detail

* feat(literary): add admin work linking primitives

* feat(catalog): group literary items by work

* feat(literary): auto-link works during book scans

* fix(literary): narrow work match candidates

* fix(literary): address work merge blockers

---------

Co-authored-by: rxwatcher <rxwatcher@users.noreply.github.com>
Co-authored-by: Quick <31828688+Quick104@users.noreply.github.com>
2026-06-16 18:17:08 -04:00

48 lines
843 B
Go

package literaryworks
import (
"strings"
"unicode"
)
var leadingArticles = map[string]struct{}{
"a": {},
"an": {},
"the": {},
}
func normalizeKey(value string) string {
value = strings.ToLower(strings.TrimSpace(value))
var b strings.Builder
lastSpace := true
for _, r := range value {
if unicode.IsLetter(r) || unicode.IsDigit(r) {
b.WriteRune(r)
lastSpace = false
continue
}
if !lastSpace {
b.WriteByte(' ')
lastSpace = true
}
}
parts := strings.Fields(b.String())
filtered := parts[:0]
for _, part := range parts {
if _, ok := leadingArticles[part]; ok {
continue
}
filtered = append(filtered, part)
}
return strings.Join(filtered, " ")
}
func personKey(names []string) string {
for _, name := range names {
if key := normalizeKey(name); key != "" {
return key
}
}
return ""
}