2020-01-19 06:06:00 +00:00
|
|
|
package arguments
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
|
|
|
"regexp"
|
2020-01-25 02:49:33 +00:00
|
|
|
"unicode/utf16"
|
2020-01-19 06:06:00 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
EmojiRegex = regexp.MustCompile(`<(a?):(.+?):(\d+)>`)
|
|
|
|
|
|
|
|
ErrInvalidEmoji = errors.New("Invalid emoji")
|
|
|
|
)
|
|
|
|
|
|
|
|
type Emoji struct {
|
|
|
|
ID string
|
|
|
|
|
|
|
|
Custom bool
|
|
|
|
Name string
|
|
|
|
Animated bool
|
|
|
|
}
|
|
|
|
|
2020-01-24 04:01:59 +00:00
|
|
|
func (e Emoji) APIString() string {
|
2020-01-24 03:54:47 +00:00
|
|
|
if !e.Custom {
|
|
|
|
return e.ID
|
|
|
|
}
|
|
|
|
|
|
|
|
return e.Name + ":" + e.ID
|
|
|
|
}
|
|
|
|
|
2020-01-24 04:01:59 +00:00
|
|
|
func (e Emoji) String() string {
|
|
|
|
if !e.Custom {
|
|
|
|
return e.ID
|
|
|
|
}
|
|
|
|
|
|
|
|
if e.Animated {
|
|
|
|
return "<a:" + e.Name + ":" + e.ID + ">"
|
|
|
|
} else {
|
|
|
|
return "<:" + e.Name + ":" + e.ID + ">"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-24 03:54:47 +00:00
|
|
|
func (e Emoji) URL() string {
|
|
|
|
if e.Custom {
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
|
|
|
base := "https://cdn.discordapp.com/emojis/" + e.ID
|
|
|
|
|
|
|
|
if e.Animated {
|
|
|
|
return base + ".gif"
|
|
|
|
} else {
|
|
|
|
return base + ".png"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-19 06:06:00 +00:00
|
|
|
func (e *Emoji) Parse(arg string) error {
|
2020-01-25 02:49:33 +00:00
|
|
|
// Check if Unicode emoji
|
|
|
|
if stringIsEmojiOnly(arg) {
|
|
|
|
e.ID = arg
|
2020-01-19 06:06:00 +00:00
|
|
|
e.Custom = false
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
var matches = EmojiRegex.FindStringSubmatch(arg)
|
|
|
|
|
|
|
|
if len(matches) != 4 {
|
|
|
|
return ErrInvalidEmoji
|
|
|
|
}
|
|
|
|
|
|
|
|
e.Custom = true
|
|
|
|
e.Animated = matches[1] == "a"
|
|
|
|
e.Name = matches[2]
|
|
|
|
e.ID = matches[3]
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
2020-01-25 02:49:33 +00:00
|
|
|
|
|
|
|
func stringIsEmojiOnly(emoji string) bool {
|
|
|
|
runes := []rune(emoji)
|
|
|
|
// Slice of runes is 2, since some emojis have 2 runes.
|
|
|
|
if len(runes) > 2 {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
return emojiRune(runes[0])
|
|
|
|
}
|
|
|
|
|
|
|
|
var surrogates = [...][2]rune{ // [0] from, [1] to
|
|
|
|
{utf16.DecodeRune(0xD83C, 0xD000), utf16.DecodeRune(0xD83C, 0xDFFF)},
|
|
|
|
{utf16.DecodeRune(0xD83E, 0xD000), utf16.DecodeRune(0xD83E, 0xDFFF)},
|
|
|
|
{utf16.DecodeRune(0xD83F, 0xD000), utf16.DecodeRune(0xD83F, 0xDFFF)},
|
|
|
|
}
|
|
|
|
|
|
|
|
func emojiRune(r rune) bool {
|
|
|
|
b := r == '\u00a9' || r == '\u00ae' ||
|
|
|
|
(r >= '\u2000' && r <= '\u3300')
|
|
|
|
if b {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, surrogate := range surrogates {
|
|
|
|
if surrogate[0] <= r && r <= surrogate[1] {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false
|
|
|
|
}
|