kaiyan/emote/emote.go
2025-04-20 22:22:51 -04:00

66 lines
1.7 KiB
Go

package emote
import (
"strings"
"unicode"
)
// Emote is the information Kaiyan needs about an emote.
type Emote struct {
// ID is the emote ID per the source.
ID string `json:"id"`
// Name is the text of the emote as would be parsed from message text.
Name string `json:"name"`
// Source is the name of the emote source, e.g. "7TV", "Twitch:cirno_tv", &c.
Source string `json:"source"`
// Link is a hyperlink to manage the emote.
Link string `json:"link"`
// Image is a hyperlink to the emote image of any size.
Image string `json:"image"`
}
// Parser finds emotes in a message.
//
// Parser assumes that emotes are bound by whitespace.
type Parser struct {
m map[string]Emote
// TODO(branden): more efficient data structure; trie?
}
// NewParser creates a Parser for the given list of emotes.
func NewParser(emotes ...Emote) Parser {
m := make(map[string]Emote, len(emotes))
for _, e := range emotes {
m[e.Name] = e
}
return Parser{m}
}
// Next parses the next emote instance from the message and returns the
// remainder of the message text following it.
// If there is no emote in the message the returned emote has an empty ID.
func (p Parser) Next(text string) (emote Emote, following string) {
for text != "" {
// First trim any existing space.
text = strings.TrimSpace(text)
// Then look for the next space.
// If there is none, this is the last word of the message; we still
// need to look it up.
k := strings.IndexFunc(text, unicode.IsSpace)
word := text
if k >= 0 {
word = text[:k]
following = text[k:]
} else {
following = ""
}
em := p.m[word]
if em.ID != "" {
return em, following
}
text = following
}
// No emote found.
return Emote{}, ""
}