Fix emotes

This reworks how emotes are cached in relation to their physical
location on disk.  Functionally, they should be the same from the user
perspective but it sets up some stuff that will make it easier to add
emotes from various sources.
This commit is contained in:
Zorchenhimer 2019-06-18 22:13:53 -04:00
parent 35774b061f
commit a73375f152
7 changed files with 128 additions and 105 deletions

View File

@ -438,19 +438,27 @@ var commands = &CommandControl{
common.CNReloadEmotes.String(): Command{
HelpText: "Reload the emotes on the server.",
Function: func(cl *Client, args []string) (string, error) {
go func() {
cl.SendServerMessage("Reloading emotes")
err := loadEmotes()
if err != nil {
common.LogErrorf("Unbale to reload emotes: %s\n", err)
return "", err
//return "", err
cl.SendChatData(common.NewChatMessage("", "",
err.Error(),
common.CmdlUser, common.MsgCommandResponse))
return
}
cl.belongsTo.AddChatMsg(common.NewChatHiddenMessage(common.CdEmote, common.Emotes))
cl.belongsTo.AddModNotice(cl.name + " has reloaded emotes")
num := len(Emotes)
num := len(common.Emotes)
common.LogInfof("Loaded %d emotes\n", num)
return fmt.Sprintf("Emotes loaded: %d", num), nil
cl.belongsTo.AddModNotice(fmt.Sprintf("%s reloaded %d emotes.", cl.name, num))
}()
return "Reloading emotes...", nil
},
},

View File

@ -40,7 +40,7 @@ func newChatRoom() (*ChatRoom, error) {
if err != nil {
return nil, fmt.Errorf("error loading emotes: %s", err)
}
common.LogInfof("Loaded %d emotes\n", len(Emotes))
common.LogInfof("Loaded %d emotes\n", len(common.Emotes))
//the "heartbeat" for broadcasting messages
go cr.Broadcast()

View File

@ -2,19 +2,41 @@ package common
import (
"fmt"
"path"
"path/filepath"
"regexp"
"strings"
)
var Emotes map[string]EmotePath
type EmotesMap map[string]string
type EmotePath struct {
Dir string
File string
var Emotes EmotesMap
var reStripStatic = regexp.MustCompile(`^(\\|/)?static`)
func init() {
Emotes = map[string]string{}
}
func (e EmotePath) path() string {
return path.Join(e.Dir, e.File)
func (em EmotesMap) Add(fullpath string) {
fullpath = reStripStatic.ReplaceAllLiteralString(fullpath, "")
base := filepath.Base(fullpath)
code := base[0 : len(base)-len(filepath.Ext(base))]
_, exists := em[code]
num := 0
for exists {
num += 1
_, exists = em[fmt.Sprintf("%s-%d", code, num)]
}
if num > 0 {
code = fmt.Sprintf("%s-%d", code, num)
}
Emotes[code] = fullpath
fmt.Printf("Added emote %s at path %q\n", code, fullpath)
}
func EmoteToHtml(file, title string) string {
@ -30,7 +52,7 @@ func ParseEmotesArray(words []string) []string {
found := false
for key, val := range Emotes {
if key == wordTrimmed {
newWords = append(newWords, EmoteToHtml(val.File, key))
newWords = append(newWords, EmoteToHtml(val, key))
found = true
}
}

View File

@ -1,6 +1,7 @@
package common
import (
"os"
"testing"
)
@ -25,21 +26,12 @@ var data_good = map[string]string{
}
func TestMain(m *testing.M) {
Emotes = map[string]EmotePath{
"one": EmotePath{
Dir: "",
File: "one.png",
},
"two": EmotePath{
Dir: "",
File: "two.png",
},
"three": EmotePath{
Dir: "",
File: "three.gif",
},
Emotes = map[string]string{
"one": "/emotes/one.png",
"two": "/emotes/two.png",
"three": "/emotes/three.gif",
}
// os.Exit(m.Run())
os.Exit(m.Run())
}
func TestEmotes_ParseEmotes(t *testing.T) {

126
emotes.go
View File

@ -4,28 +4,19 @@ import (
"encoding/json"
"fmt"
"io"
"io/ioutil"
"log"
"net/http"
"os"
"path"
"path/filepath"
"strings"
"github.com/pkg/errors"
"github.com/zorchenhimer/MovieNight/common"
)
const emoteDir = "./static/emotes/"
var Emotes map[string]Emote
type Emote struct {
Dir string
File string
}
func (e Emote) path() string {
return path.Join(e.Dir, e.File)
}
type TwitchUser struct {
ID string
Login string
@ -36,74 +27,85 @@ type EmoteInfo struct {
Code string
}
// func loadEmotes() error {
// newEmotes := map[string]string{}
// emotePNGs, err := filepath.Glob("./static/emotes/*.png")
// if err != nil {
// return 0, fmt.Errorf("unable to glob emote directory: %s\n", err)
// }
// emoteGIFs, err := filepath.Glob("./static/emotes/*.gif")
// if err != nil {
// return 0, fmt.Errorf("unable to glob emote directory: %s\n", err)
// }
// globbed_files := []string(emotePNGs)
// globbed_files = append(globbed_files, emoteGIFs...)
// LogInfoln("Loading emotes...")
// emInfo := []string{}
// for _, file := range globbed_files {
// file = filepath.Base(file)
// key := file[0 : len(file)-4]
// newEmotes[key] = file
// emInfo = append(emInfo, key)
// }
// Emotes = newEmotes
// LogInfoln(strings.Join(emInfo, " "))
// return len(Emotes), nil
// }
func loadEmotes() error {
fmt.Println(processEmoteDir(emoteDir))
//fmt.Println(processEmoteDir(emoteDir))
err := processEmoteDir(emoteDir)
if err != nil {
return err
}
return nil
}
func processEmoteDir(path string) ([]Emote, error) {
dir, err := os.Open(path)
func processEmoteDir(path string) error {
dirInfo, err := ioutil.ReadDir(path)
if err != nil {
return nil, errors.Wrap(err, "could not open emoteDir:")
return errors.Wrap(err, "could not open emoteDir:")
}
files, err := dir.Readdir(0)
subDirs := []string{}
for _, item := range dirInfo {
// Get first level subdirs (eg, "twitch", "discord", etc)
if item.IsDir() {
subDirs = append(subDirs, item.Name())
continue
}
}
// Find top level emotes
err = findEmotes(path)
if err != nil {
return nil, errors.Wrap(err, "could not get files:")
return errors.Wrap(err, "could not findEmotes() in top level directory:")
}
var emotes []Emote
for _, file := range files {
emotes = append(emotes, Emote{Dir: path, File: file.Name()})
}
subdir, err := dir.Readdirnames(0)
// Get second level subdirs (eg, "twitch", "zorchenhimer", etc)
for _, dir := range subDirs {
subd, err := ioutil.ReadDir(filepath.Join(path, dir))
if err != nil {
return nil, errors.Wrap(err, "could not get sub directories:")
continue
}
for _, d := range subd {
if d.IsDir() {
//emotes = append(emotes, findEmotes(filepath.Join(path, dir, d.Name()))...)
findEmotes(filepath.Join(path, dir, d.Name()))
}
}
}
for _, d := range subdir {
subEmotes, err := processEmoteDir(d)
return nil
}
func findEmotes(dir string) error {
fmt.Printf("finding emotes in %q\n", dir)
emotePNGs, err := filepath.Glob(filepath.Join(dir, "*.png"))
if err != nil {
return nil, errors.Wrapf(err, "could not process sub directory \"%s\":", d)
//return 0, fmt.Errorf("unable to glob emote directory: %s\n", err)
return nil
}
emotes = append(emotes, subEmotes...)
fmt.Printf("%d emotePNGs\n", len(emotePNGs))
emoteGIFs, err := filepath.Glob(filepath.Join(dir, "*.gif"))
if err != nil {
return errors.Wrap(err, "unable to glob emote directory:")
}
fmt.Printf("%d emoteGIFs\n", len(emoteGIFs))
for _, file := range emotePNGs {
common.Emotes.Add(file)
//emotes = append(emotes, common.Emote{FullPath: dir, Code: file})
}
return emotes, nil
for _, file := range emoteGIFs {
common.Emotes.Add(file)
}
return nil
}
func getEmotes(names []string) error {
users := getUserIDs(names)
users = append(users, TwitchUser{ID: "0", Login: "global"})
users = append(users, TwitchUser{ID: "0", Login: "twitch"})
for _, user := range users {
emotes, cheers, err := getChannelEmotes(user.ID)
@ -111,14 +113,14 @@ func getEmotes(names []string) error {
return errors.Wrapf(err, "could not get emote data for \"%s\"", user.ID)
}
emoteUserDir := path.Join(emoteDir, "twitch", user.Login)
emoteUserDir := filepath.Join(emoteDir, "twitch", user.Login)
if _, err := os.Stat(emoteUserDir); os.IsNotExist(err) {
os.MkdirAll(emoteUserDir, os.ModePerm)
}
for _, emote := range emotes {
if !strings.ContainsAny(emote.Code, `:;\[]|?&`) {
filePath := path.Join(emoteUserDir, emote.Code+".png")
filePath := filepath.Join(emoteUserDir, emote.Code+".png")
file, err := os.Create(filePath)
if err != nil {
@ -134,7 +136,7 @@ func getEmotes(names []string) error {
for amount, sizes := range cheers {
name := fmt.Sprintf("%sCheer%s.gif", user.Login, amount)
filePath := path.Join(emoteUserDir, name)
filePath := filepath.Join(emoteUserDir, name)
file, err := os.Create(filePath)
if err != nil {
return errors.Wrapf(err, "could not create emote file in path \"%s\":", filePath)

View File

@ -79,8 +79,7 @@ func wsImages(w http.ResponseWriter, r *http.Request) {
}
func wsEmotes(w http.ResponseWriter, r *http.Request) {
emotefile := filepath.Base(r.URL.Path)
http.ServeFile(w, r, path.Join(emoteDir, emotefile))
http.ServeFile(w, r, path.Join("./static/", r.URL.Path))
}
// Handling the websocket