diff --git a/chatcommands.go b/chatcommands.go index c18b6e3..40fa62a 100644 --- a/chatcommands.go +++ b/chatcommands.go @@ -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) { - cl.SendServerMessage("Reloading emotes") - err := loadEmotes() - if err != nil { - common.LogErrorf("Unbale to reload emotes: %s\n", err) - return "", err - } + go func() { + cl.SendServerMessage("Reloading emotes") + err := loadEmotes() + if err != nil { + common.LogErrorf("Unbale to reload emotes: %s\n", err) + //return "", err - cl.belongsTo.AddChatMsg(common.NewChatHiddenMessage(common.CdEmote, common.Emotes)) - cl.belongsTo.AddModNotice(cl.name + " has reloaded emotes") + cl.SendChatData(common.NewChatMessage("", "", + err.Error(), + common.CmdlUser, common.MsgCommandResponse)) + return + } - num := len(Emotes) - common.LogInfof("Loaded %d emotes\n", num) - return fmt.Sprintf("Emotes loaded: %d", num), nil + cl.belongsTo.AddChatMsg(common.NewChatHiddenMessage(common.CdEmote, common.Emotes)) + cl.belongsTo.AddModNotice(cl.name + " has reloaded emotes") + + num := len(common.Emotes) + common.LogInfof("Loaded %d emotes\n", num) + cl.belongsTo.AddModNotice(fmt.Sprintf("%s reloaded %d emotes.", cl.name, num)) + }() + return "Reloading emotes...", nil }, }, diff --git a/chatroom.go b/chatroom.go index 1111189..c0c6342 100644 --- a/chatroom.go +++ b/chatroom.go @@ -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() diff --git a/common/emotes.go b/common/emotes.go index 3bff321..fd49224 100644 --- a/common/emotes.go +++ b/common/emotes.go @@ -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 } } diff --git a/common/emotes_test.go b/common/emotes_test.go index 376dadb..bb31646 100644 --- a/common/emotes_test.go +++ b/common/emotes_test.go @@ -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) { diff --git a/emotes.go b/emotes.go index c9a0431..34e80df 100644 --- a/emotes.go +++ b/emotes.go @@ -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) - if err != nil { - return nil, errors.Wrap(err, "could not get files:") - } + subDirs := []string{} - var emotes []Emote - for _, file := range files { - emotes = append(emotes, Emote{Dir: path, File: file.Name()}) - } - - subdir, err := dir.Readdirnames(0) - if err != nil { - return nil, errors.Wrap(err, "could not get sub directories:") - } - - for _, d := range subdir { - subEmotes, err := processEmoteDir(d) - if err != nil { - return nil, errors.Wrapf(err, "could not process sub directory \"%s\":", d) + for _, item := range dirInfo { + // Get first level subdirs (eg, "twitch", "discord", etc) + if item.IsDir() { + subDirs = append(subDirs, item.Name()) + continue } - emotes = append(emotes, subEmotes...) } - return emotes, nil + // Find top level emotes + err = findEmotes(path) + if err != nil { + return errors.Wrap(err, "could not findEmotes() in top level directory:") + } + + // Get second level subdirs (eg, "twitch", "zorchenhimer", etc) + for _, dir := range subDirs { + subd, err := ioutil.ReadDir(filepath.Join(path, dir)) + if err != nil { + 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())) + } + } + } + + 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 0, fmt.Errorf("unable to glob emote directory: %s\n", err) + return nil + } + 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}) + } + + 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) diff --git a/handlers.go b/handlers.go index a7da689..fbbcc41 100644 --- a/handlers.go +++ b/handlers.go @@ -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 diff --git a/settings_example.json b/settings_example.json index 9700d7b..ea69bc9 100644 --- a/settings_example.json +++ b/settings_example.json @@ -1,6 +1,6 @@ { "MaxMessageCount": 300, - "TitleLength": 50, + "TitleLength": 50, "AdminPassword": "", "Bans": [], "StreamKey": "ALongStreamKey",