emoji.go 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. package chat
  2. import (
  3. "bytes"
  4. "strings"
  5. "sync"
  6. "text/template"
  7. "time"
  8. emojiDef "github.com/yuin/goldmark-emoji/definition"
  9. )
  10. // implements the emojiDef.Emojis interface but uses case-insensitive search.
  11. // the .children field isn't currently used, but could be used in a future
  12. // implementation of say, emoji packs where a child represents a pack.
  13. type emojis struct {
  14. list []emojiDef.Emoji
  15. names map[string]*emojiDef.Emoji
  16. children []emojiDef.Emojis
  17. emojiMu sync.Mutex
  18. emojiDefs emojiDef.Emojis
  19. emojiHTML map[string]string
  20. emojiModTime time.Time
  21. emojiHTMLFormat string
  22. emojiHTMLTemplate *template.Template
  23. }
  24. // return a new Emojis set.
  25. func newEmojis(emotes ...emojiDef.Emoji) *emojis {
  26. loadEmoji()
  27. e := &emojis{
  28. list: emotes,
  29. names: map[string]*emojiDef.Emoji{},
  30. children: []emojiDef.Emojis{},
  31. emojiMu: sync.Mutex{},
  32. emojiHTML: make(map[string]string),
  33. emojiModTime: time.Now(),
  34. emojiHTMLFormat: `<img src="{{ .URL }}" class="emoji" alt=":{{ .Name }}:" title=":{{ .Name }}:">`,
  35. emojiHTMLTemplate: template.Must(template.New("emojiHTML").Parse(emojiHTMLFormat)),
  36. }
  37. for i := range e.list {
  38. emoji := &e.list[i]
  39. for _, s := range emoji.ShortNames {
  40. e.names[s] = emoji
  41. }
  42. }
  43. return e
  44. }
  45. func (self *emojis) Get(shortName string) (*emojiDef.Emoji, bool) {
  46. v, ok := self.names[strings.ToLower(shortName)]
  47. if ok {
  48. return v, ok
  49. }
  50. for _, child := range self.children {
  51. v, ok := child.Get(shortName)
  52. if ok {
  53. return v, ok
  54. }
  55. }
  56. return nil, false
  57. }
  58. func (self *emojis) Add(emotes emojiDef.Emojis) {
  59. self.children = append(self.children, emotes)
  60. }
  61. func (self *emojis) Clone() emojiDef.Emojis {
  62. clone := &emojis{
  63. list: self.list,
  64. names: self.names,
  65. children: make([]emojiDef.Emojis, len(self.children)),
  66. }
  67. copy(clone.children, self.children)
  68. return clone
  69. }
  70. var (
  71. emojiMu sync.Mutex
  72. // emojiDefs = newEmojis()
  73. // emojiHTML = make(map[string]string)
  74. emojiModTime time.Time
  75. emojiHTMLFormat = `<img src="{{ .URL }}" class="emoji" alt=":{{ .Name }}:" title=":{{ .Name }}:">`
  76. emojiHTMLTemplate = template.Must(template.New("emojiHTML").Parse(emojiHTMLFormat))
  77. )
  78. type emojiMeta struct {
  79. emojiDefs emojiDef.Emojis
  80. emojiHTML map[string]string
  81. }
  82. func loadEmoji() emojiDef.Emojis {
  83. modTime, err := data.UpdateEmojiList(false)
  84. if err != nil {
  85. return
  86. }
  87. emojiArr := make([]emojiDef.Emoji, 0)
  88. if modTime.After(emojiModTime) {
  89. emojiMu.Lock()
  90. defer emojiMu.Unlock()
  91. emojiHTML := make(map[string]string)
  92. emojiList := data.GetEmojiList()
  93. for i := 0; i < len(emojiList); i++ {
  94. var buf bytes.Buffer
  95. err := emojiHTMLTemplate.Execute(&buf, emojiList[i])
  96. if err != nil {
  97. return
  98. }
  99. emojiHTML[strings.ToLower(emojiList[i].Name)] = buf.String()
  100. emoji := emojiDef.NewEmoji(emojiList[i].Name, nil, strings.ToLower(emojiList[i].Name))
  101. emojiArr = append(emojiArr, emoji)
  102. }
  103. }
  104. emojiDefs := newEmojis(emojiArr...)
  105. return emojiDefs
  106. }