Compare commits

..

No commits in common. "32978784212d45d96926fec70b75c5bb6c2f3bd7" and "22658949a87105db14d066b89c9025622420132d" have entirely different histories.

12 changed files with 51 additions and 320 deletions

View File

@ -6,8 +6,6 @@ import (
"fmt" "fmt"
"math/rand" "math/rand"
"net/http" "net/http"
"os"
"os/signal"
"reflect" "reflect"
"regexp" "regexp"
"strings" "strings"
@ -137,14 +135,8 @@ func New(config *config.Config, connector Connector) Bot {
func (b *bot) ListenAndServe() { func (b *bot) ListenAndServe() {
addr := b.config.Get("HttpAddr", "127.0.0.1:1337") addr := b.config.Get("HttpAddr", "127.0.0.1:1337")
stop := make(chan os.Signal, 1) log.Debug().Msgf("starting web service at %s", addr)
signal.Notify(stop, os.Interrupt) log.Fatal().Err(http.ListenAndServe(addr, b.router)).Msg("bot killed")
go func() {
log.Debug().Msgf("starting web service at %s", addr)
log.Fatal().Err(http.ListenAndServe(addr, b.router)).Msg("bot killed")
}()
<-stop
b.DefaultConnector().Shutdown()
} }
func (b *bot) RegisterWeb(r http.Handler, root string) { func (b *bot) RegisterWeb(r http.Handler, root string) {

View File

@ -191,9 +191,6 @@ type Connector interface {
// Serve starts a connector's connection routine // Serve starts a connector's connection routine
Serve() error Serve() error
// Shutdown cleans up after the connection
Shutdown()
// Who returns a user list for a channel // Who returns a user list for a channel
Who(string) []string Who(string) []string

View File

@ -27,9 +27,6 @@ type Discord struct {
// store IDs -> nick and vice versa for quick conversion // store IDs -> nick and vice versa for quick conversion
uidCache map[string]string uidCache map[string]string
registeredCmds []*discordgo.ApplicationCommand
cmdHandlers map[string]CmdHandler
} }
func New(config *config.Config) *Discord { func New(config *config.Config) *Discord {
@ -38,17 +35,10 @@ func New(config *config.Config) *Discord {
log.Fatal().Err(err).Msg("Could not connect to Discord") log.Fatal().Err(err).Msg("Could not connect to Discord")
} }
d := &Discord{ d := &Discord{
config: config, config: config,
client: client, client: client,
uidCache: map[string]string{}, uidCache: map[string]string{},
registeredCmds: []*discordgo.ApplicationCommand{},
cmdHandlers: map[string]CmdHandler{},
} }
d.client.AddHandler(func(s *discordgo.Session, i *discordgo.InteractionCreate) {
if h, ok := d.cmdHandlers[i.ApplicationCommandData().Name]; ok {
h(s, i)
}
})
return d return d
} }
func (d *Discord) GetRouter() (http.Handler, string) { func (d *Discord) GetRouter() (http.Handler, string) {
@ -400,26 +390,3 @@ func (d *Discord) SetRole(userID, roleID string) error {
} }
return d.client.GuildMemberRoleAdd(guildID, userID, roleID) return d.client.GuildMemberRoleAdd(guildID, userID, roleID)
} }
type CmdHandler func(s *discordgo.Session, i *discordgo.InteractionCreate)
func (d *Discord) RegisterSlashCmd(c discordgo.ApplicationCommand, handler CmdHandler) error {
guildID := d.config.Get("discord.guildid", "")
cmd, err := d.client.ApplicationCommandCreate(d.client.State.User.ID, guildID, &c)
d.cmdHandlers[c.Name] = handler
if err != nil {
return err
}
d.registeredCmds = append(d.registeredCmds, cmd)
return nil
}
func (d *Discord) Shutdown() {
log.Debug().Msgf("Shutting down and deleting %d slash commands", len(d.registeredCmds))
guildID := d.config.Get("discord.guildid", "")
for _, c := range d.registeredCmds {
if err := d.client.ApplicationCommandDelete(d.client.State.User.ID, guildID, c.ID); err != nil {
log.Error().Err(err).Msgf("could not delete command %s", c.Name)
}
}
}

View File

@ -359,5 +359,3 @@ func (i Irc) GetRoles() ([]bot.Role, error) {
func (i Irc) SetRole(userID, roleID string) error { func (i Irc) SetRole(userID, roleID string) error {
return nil return nil
} }
func (i Irc) Shutdown() {}

View File

@ -749,5 +749,3 @@ func (s *SlackApp) GetRoles() ([]bot.Role, error) {
func (s *SlackApp) SetRole(userID, roleID string) error { func (s *SlackApp) SetRole(userID, roleID string) error {
return nil return nil
} }
func (s *SlackApp) Shutdown() {}

View File

@ -180,7 +180,6 @@ func main() {
log.Fatal().Err(err) log.Fatal().Err(err)
} }
log.Debug().Msgf("Sending bot.Startup message")
b.Receive(client, bot.Startup, msg.Message{}) b.Receive(client, bot.Startup, msg.Message{})
b.ListenAndServe() b.ListenAndServe()

View File

@ -43,8 +43,6 @@ func (p *CliPlugin) registerWeb() {
p.bot.RegisterWebName(r, "/cli", "CLI") p.bot.RegisterWebName(r, "/cli", "CLI")
} }
func (p *CliPlugin) Shutdown() {}
func (p *CliPlugin) GetRouter() (http.Handler, string) { func (p *CliPlugin) GetRouter() (http.Handler, string) {
return nil, "" return nil, ""
} }

View File

@ -256,14 +256,14 @@ func (i *Item) Delete() error {
return err return err
} }
func (p *CounterPlugin) migrate(r bot.Request) (retVal bool) { func (p *CounterPlugin) migrate(r bot.Request) bool {
db := p.db db := p.db
nicks := []string{} nicks := []string{}
err := db.Select(&nicks, `select distinct nick from counter where userid is null`) err := db.Select(&nicks, `select distinct nick from counter where userid is null`)
if err != nil { if err != nil {
log.Error().Err(err).Msg("could not get nick list") log.Error().Err(err).Msg("could not get nick list")
return return false
} }
log.Debug().Msgf("Migrating %d nicks to IDs", len(nicks)) log.Debug().Msgf("Migrating %d nicks to IDs", len(nicks))
@ -284,7 +284,7 @@ func (p *CounterPlugin) migrate(r bot.Request) (retVal bool) {
if err := tx.Commit(); err != nil { if err := tx.Commit(); err != nil {
log.Error().Err(err).Msg("Could not migrate users") log.Error().Err(err).Msg("Could not migrate users")
} }
return return false
} }
func setupDB(b bot.Bot) error { func setupDB(b bot.Bot) error {

View File

@ -2,12 +2,8 @@ package cowboy
import ( import (
"fmt" "fmt"
"github.com/bwmarrin/discordgo"
"github.com/velour/catbase/plugins/emojy"
"regexp" "regexp"
"github.com/velour/catbase/connectors/discord"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
"github.com/velour/catbase/bot" "github.com/velour/catbase/bot"
"github.com/velour/catbase/config" "github.com/velour/catbase/config"
@ -21,8 +17,6 @@ type Cowboy struct {
baseEmojyURL string baseEmojyURL string
} }
var defaultOverlays = map[string]string{"hat": "hat"}
func New(b bot.Bot) *Cowboy { func New(b bot.Bot) *Cowboy {
emojyPath := b.Config().Get("emojy.path", "emojy") emojyPath := b.Config().Get("emojy.path", "emojy")
baseURL := b.Config().Get("emojy.baseURL", "/emojy/file") baseURL := b.Config().Get("emojy.baseURL", "/emojy/file")
@ -39,28 +33,6 @@ func New(b bot.Bot) *Cowboy {
func (p *Cowboy) register() { func (p *Cowboy) register() {
tbl := bot.HandlerTable{ tbl := bot.HandlerTable{
{
Kind: bot.Startup, IsCmd: false,
Regex: regexp.MustCompile(`.*`),
Handler: func(r bot.Request) bool {
log.Debug().Msgf("Got bot.Startup")
switch conn := r.Conn.(type) {
case *discord.Discord:
log.Debug().Msg("Found a discord connection")
p.registerCmds(conn)
}
return false
},
},
{
Kind: bot.Message, IsCmd: true,
Regex: regexp.MustCompile(`(?i)^:cowboy_clear_cache:$`),
Handler: func(r bot.Request) bool {
cowboyClearCache()
p.b.Send(r.Conn, bot.Ephemeral, r.Msg.Channel, r.Msg.User.ID, ":cowboy_cache_cleared:")
return true
},
},
{ {
Kind: bot.Message, IsCmd: false, Kind: bot.Message, IsCmd: false,
Regex: regexp.MustCompile(`(?i)^:cowboy_(?P<what>.+):$`), Regex: regexp.MustCompile(`(?i)^:cowboy_(?P<what>.+):$`),
@ -74,16 +46,6 @@ func (p *Cowboy) register() {
} }
func (p *Cowboy) makeCowboy(r bot.Request) { func (p *Cowboy) makeCowboy(r bot.Request) {
what := r.Values["what"]
// This'll add the image to the cowboy_cache before discord tries to access it over http
overlays := p.c.GetMap("cowboy.overlays", defaultOverlays)
hat := overlays["hat"]
i, err := cowboy(p.emojyPath, p.baseEmojyURL, hat, what)
if err != nil {
log.Error().Err(err).Msg(":cowboy_fail:")
p.b.Send(r.Conn, bot.Ephemeral, r.Msg.Channel, r.Msg.User.ID, "Hey cowboy, that image wasn't there.")
return
}
log.Debug().Msgf("makeCowboy: %s", r.Values["what"]) log.Debug().Msgf("makeCowboy: %s", r.Values["what"])
base := p.c.Get("baseURL", "http://127.0.0.1:1337") base := p.c.Get("baseURL", "http://127.0.0.1:1337")
u := base + "/cowboy/img/" + r.Values["what"] u := base + "/cowboy/img/" + r.Values["what"]
@ -91,107 +53,7 @@ func (p *Cowboy) makeCowboy(r bot.Request) {
p.b.Send(r.Conn, bot.Message, r.Msg.Channel, "", bot.ImageAttachment{ p.b.Send(r.Conn, bot.Message, r.Msg.Channel, "", bot.ImageAttachment{
URL: u, URL: u,
AltTxt: fmt.Sprintf("%s: %s", r.Msg.User.Name, r.Msg.Body), AltTxt: fmt.Sprintf("%s: %s", r.Msg.User.Name, r.Msg.Body),
Width: i.Bounds().Max.X, Width: 64,
Height: i.Bounds().Max.Y, Height: 64,
}) })
} }
func (p *Cowboy) registerCmds(d *discord.Discord) {
log.Debug().Msg("About to register some startup commands")
cmd := discordgo.ApplicationCommand{
Name: "cowboy",
Description: "cowboy-ify an emojy",
Options: []*discordgo.ApplicationCommandOption{
{
Type: discordgo.ApplicationCommandOptionString,
Name: "emojy",
Description: "which emojy you want cowboied",
Required: true,
},
},
}
overlays := p.c.GetMap("cowboy.overlays", defaultOverlays)
hat := overlays["hat"]
log.Debug().Msgf("Overlay: %s", hat)
if err := d.RegisterSlashCmd(cmd, p.mkOverlayCB(hat)); err != nil {
log.Error().Err(err).Msg("could not register cowboy command")
}
if p.c.GetInt("cowboy.overlaysEnabled", 0) == 0 {
return
}
cmd = discordgo.ApplicationCommand{
Name: "overlay",
Description: "overlay-ify an emojy",
Options: []*discordgo.ApplicationCommandOption{
{
Type: discordgo.ApplicationCommandOptionString,
Name: "overlay",
Description: "which overlay you want",
Required: true,
},
{
Type: discordgo.ApplicationCommandOptionString,
Name: "emojy",
Description: "which emojy you want overlaid",
Required: true,
},
},
}
if err := d.RegisterSlashCmd(cmd, p.mkOverlayCB("")); err != nil {
log.Error().Err(err).Msg("could not register cowboy command")
}
}
func (p *Cowboy) mkOverlayCB(overlay string) func(s *discordgo.Session, i *discordgo.InteractionCreate) {
return func(s *discordgo.Session, i *discordgo.InteractionCreate) {
lastEmojy := p.c.Get("cowboy.lastEmojy", "rust")
emojyPlugin := emojy.NewAPI(p.b)
name := i.ApplicationCommandData().Options[0].StringValue()
if overlay == "" {
overlay = name
name = i.ApplicationCommandData().Options[1].StringValue()
}
msg := fmt.Sprintf("You asked for %s overlaid by %s", name, overlay)
log.Debug().Msgf("got a cowboy command for %s overlaid by %s replacing %s",
name, overlay, lastEmojy)
prefix := overlay
newEmojy, err := cowboy(p.emojyPath, p.baseEmojyURL, overlay, name)
if err != nil {
msg = err.Error()
goto resp
}
err = emojyPlugin.RmEmojy(p.b.DefaultConnector(), lastEmojy)
if err != nil {
msg = err.Error()
goto resp
}
if overlay == "hat" {
prefix = "cowboy"
}
name = emojy.SanitizeName(prefix + "_" + name)
err = emojyPlugin.UploadEmojyImage(p.b.DefaultConnector(), name, newEmojy)
if err != nil {
msg = err.Error()
goto resp
}
p.c.Set("cowboy.lastEmojy", name)
msg = fmt.Sprintf("You replaced %s with a new emojy %s, pardner!", lastEmojy, name)
resp:
s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Content: msg,
Flags: uint64(discordgo.MessageFlagsEphemeral),
},
})
}
}

View File

@ -9,18 +9,12 @@ import (
"math" "math"
"os" "os"
"path" "path"
"sync"
"github.com/nfnt/resize" "github.com/nfnt/resize"
"github.com/rs/zerolog/log" "github.com/velour/catbase/config"
"github.com/velour/catbase/plugins/emojy" "github.com/velour/catbase/plugins/emojy"
) )
var (
cowboyCache = map[string]image.Image{}
cowboyMutex = sync.Mutex{}
)
func getEmojy(emojyPath, baseEmojyURL, name string) (image.Image, error) { func getEmojy(emojyPath, baseEmojyURL, name string) (image.Image, error) {
files, _, err := emojy.AllFiles(emojyPath, baseEmojyURL) files, _, err := emojy.AllFiles(emojyPath, baseEmojyURL)
if err != nil { if err != nil {
@ -41,17 +35,10 @@ func getEmojy(emojyPath, baseEmojyURL, name string) (image.Image, error) {
return img, nil return img, nil
} }
func getCowboyHat(emojyPath, overlay string) (image.Image, error) { func getCowboyHat(c *config.Config, emojyPath string) (image.Image, error) {
emojies, _, err := emojy.AllFiles(emojyPath, "") p := path.Join(emojyPath, c.Get("cowboy.hatname", "hat.png"))
if err != nil { p = path.Clean(p)
return nil, err f, err := os.Open(p)
}
overlay, ok := emojies[overlay]
if !ok {
return nil, fmt.Errorf("could not find overlay %s", overlay)
}
overlay = path.Clean(overlay)
f, err := os.Open(overlay)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -62,8 +49,8 @@ func getCowboyHat(emojyPath, overlay string) (image.Image, error) {
return img, nil return img, nil
} }
func cowboyifyImage(emojyPath, overlay string, input image.Image) (image.Image, error) { func cowboyifyImage(c *config.Config, emojyPath string, input image.Image) (image.Image, error) {
hat, err := getCowboyHat(emojyPath, overlay) hat, err := getCowboyHat(c, emojyPath)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -78,27 +65,12 @@ func cowboyifyImage(emojyPath, overlay string, input image.Image) (image.Image,
return dst, nil return dst, nil
} }
func cowboy(emojyPath, baseEmojyURL, overlay, name string) (image.Image, error) { func cowboy(c *config.Config, emojyPath, baseEmojyURL, name string) ([]byte, error) {
cowboyMutex.Lock() emojy, err := getEmojy(emojyPath, baseEmojyURL, name)
defer cowboyMutex.Unlock()
if img, ok := cowboyCache[name]; ok {
log.Debug().Msgf(":cowboy_using_cached_image: %s", name)
return img, nil
}
log.Debug().Msgf(":cowboy_generating_image: %s with overlay %s", name, overlay)
emjy, err := getEmojy(emojyPath, baseEmojyURL, name)
if err != nil { if err != nil {
return nil, err return nil, err
} }
img, err := cowboyifyImage(emojyPath, overlay, emjy) img, err := cowboyifyImage(c, emojyPath, emojy)
if err != nil {
return nil, err
}
cowboyCache[name] = img
return img, nil
}
func encode(img image.Image, err error) ([]byte, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -109,9 +81,3 @@ func encode(img image.Image, err error) ([]byte, error) {
} }
return w.Bytes(), nil return w.Bytes(), nil
} }
func cowboyClearCache() {
cowboyMutex.Lock()
defer cowboyMutex.Unlock()
cowboyCache = map[string]image.Image{}
}

View File

@ -9,22 +9,15 @@ import (
func (p *Cowboy) registerWeb() { func (p *Cowboy) registerWeb() {
r := chi.NewRouter() r := chi.NewRouter()
r.HandleFunc("/img/{overlay}/{what}", p.handleImage) r.HandleFunc("/img/{what}", p.handleImage)
p.b.RegisterWeb(r, "/cowboy") p.b.RegisterWeb(r, "/cowboy")
} }
func (p *Cowboy) handleImage(w http.ResponseWriter, r *http.Request) { func (p *Cowboy) handleImage(w http.ResponseWriter, r *http.Request) {
what := chi.URLParam(r, "what") what := chi.URLParam(r, "what")
overlay := chi.URLParam(r, "overlay") img, err := cowboy(p.c, p.emojyPath, p.baseEmojyURL, what)
overlays := p.c.GetMap("cowboy.overlays", defaultOverlays)
overlayPath, ok := overlays[overlay]
if !ok {
w.WriteHeader(http.StatusNotFound)
return
}
img, err := encode(cowboy(p.emojyPath, p.baseEmojyURL, overlayPath, what))
if err != nil { if err != nil {
w.WriteHeader(http.StatusInternalServerError) w.WriteHeader(500)
fmt.Fprintf(w, "Error: %s", err) fmt.Fprintf(w, "Error: %s", err)
return return
} }

View File

@ -4,8 +4,6 @@ import (
"bytes" "bytes"
"encoding/base64" "encoding/base64"
"fmt" "fmt"
"image"
"image/draw"
"math" "math"
"os" "os"
"path" "path"
@ -36,14 +34,7 @@ type EmojyPlugin struct {
const maxLen = 32 const maxLen = 32
func New(b bot.Bot) *EmojyPlugin { func New(b bot.Bot) *EmojyPlugin {
p := NewAPI(b) log.Debug().Msgf("emojy.New")
p.register()
p.registerWeb()
return p
}
// NewAPI creates a version used only for API purposes (no callbacks registered)
func NewAPI(b bot.Bot) *EmojyPlugin {
emojyPath := b.Config().Get("emojy.path", "emojy") emojyPath := b.Config().Get("emojy.path", "emojy")
baseURL := b.Config().Get("emojy.baseURL", "/emojy/file") baseURL := b.Config().Get("emojy.baseURL", "/emojy/file")
p := &EmojyPlugin{ p := &EmojyPlugin{
@ -54,6 +45,8 @@ func NewAPI(b bot.Bot) *EmojyPlugin {
baseURL: baseURL, baseURL: baseURL,
} }
p.setupDB() p.setupDB()
p.register()
p.registerWeb()
return p return p
} }
@ -93,10 +86,10 @@ func (p *EmojyPlugin) register() {
Kind: bot.Message, IsCmd: true, Kind: bot.Message, IsCmd: true,
Regex: regexp.MustCompile(`(?i)^swapemojy (?P<old>.+) (?P<new>.+)$`), Regex: regexp.MustCompile(`(?i)^swapemojy (?P<old>.+) (?P<new>.+)$`),
Handler: func(r bot.Request) bool { Handler: func(r bot.Request) bool {
old := SanitizeName(r.Values["old"]) old := sanitizeName(r.Values["old"])
new := SanitizeName(r.Values["new"]) new := sanitizeName(r.Values["new"])
p.rmEmojyHandler(r, old) p.rmEmojy(r, old)
p.addEmojyHandler(r, new) p.addEmojy(r, new)
return true return true
}, },
}, },
@ -104,57 +97,46 @@ func (p *EmojyPlugin) register() {
Kind: bot.Message, IsCmd: true, Kind: bot.Message, IsCmd: true,
Regex: regexp.MustCompile(`(?i)^addemojy (?P<name>.+)$`), Regex: regexp.MustCompile(`(?i)^addemojy (?P<name>.+)$`),
Handler: func(r bot.Request) bool { Handler: func(r bot.Request) bool {
name := SanitizeName(r.Values["name"]) name := sanitizeName(r.Values["name"])
return p.addEmojyHandler(r, name) return p.addEmojy(r, name)
}, },
}, },
{ {
Kind: bot.Message, IsCmd: true, Kind: bot.Message, IsCmd: true,
Regex: regexp.MustCompile(`(?i)^rmemojy (?P<name>.+)$`), Regex: regexp.MustCompile(`(?i)^rmemojy (?P<name>.+)$`),
Handler: func(r bot.Request) bool { Handler: func(r bot.Request) bool {
name := SanitizeName(r.Values["name"]) name := sanitizeName(r.Values["name"])
return p.rmEmojyHandler(r, name) return p.rmEmojy(r, name)
}, },
}, },
} }
p.b.RegisterTable(p, ht) p.b.RegisterTable(p, ht)
} }
func (p *EmojyPlugin) RmEmojy(c bot.Connector, name string) error { func (p *EmojyPlugin) rmEmojy(r bot.Request, name string) bool {
onServerList := invertEmojyList(p.b.GetEmojiList(false)) onServerList := invertEmojyList(p.b.GetEmojiList(false))
// Call a non-existent emojy a successful remove
if _, ok := onServerList[name]; !ok { if _, ok := onServerList[name]; !ok {
return fmt.Errorf("could not find emojy %s", name)
}
if err := c.DeleteEmojy(name); err != nil {
return err
}
return nil
}
func (p *EmojyPlugin) rmEmojyHandler(r bot.Request, name string) bool {
err := p.RmEmojy(r.Conn, name)
if err != nil {
p.b.Send(r.Conn, bot.Message, r.Msg.Channel, "Emoji does not exist") p.b.Send(r.Conn, bot.Message, r.Msg.Channel, "Emoji does not exist")
return true return true
} }
if err := r.Conn.DeleteEmojy(name); err != nil {
p.b.Send(r.Conn, bot.Message, r.Msg.Channel, "error "+err.Error())
return true
}
p.b.Send(r.Conn, bot.Message, r.Msg.Channel, "removed emojy "+name) p.b.Send(r.Conn, bot.Message, r.Msg.Channel, "removed emojy "+name)
return true return true
} }
func (p *EmojyPlugin) AddEmojy(c bot.Connector, name string) error { func (p *EmojyPlugin) addEmojy(r bot.Request, name string) bool {
onServerList := invertEmojyList(p.b.GetEmojiList(false)) onServerList := invertEmojyList(p.b.GetEmojiList(false))
if _, ok := onServerList[name]; ok { if _, ok := onServerList[name]; ok {
return fmt.Errorf("emojy already exists") p.b.Send(r.Conn, bot.Message, r.Msg.Channel, "Emoji already exists")
return true
} }
if err := p.UploadEmojyInCache(c, name); err != nil { if err := p.uploadEmojy(r.Conn, name); err != nil {
return err p.b.Send(r.Conn, bot.Message, r.Msg.Channel, fmt.Sprintf("error adding emojy: %v", err))
return true
} }
return nil
}
func (p *EmojyPlugin) addEmojyHandler(r bot.Request, name string) bool {
p.AddEmojy(r.Conn, name)
list := r.Conn.GetEmojiList(true) list := r.Conn.GetEmojiList(true)
for k, v := range list { for k, v := range list {
if v == name { if v == name {
@ -251,44 +233,23 @@ func isEmoji(in string) bool {
return gomoji.ContainsEmoji(in) return gomoji.ContainsEmoji(in)
} }
func (p *EmojyPlugin) UploadEmojyInCache(c bot.Connector, name string) error { func (p *EmojyPlugin) uploadEmojy(c bot.Connector, name string) error {
maxEmojySz := p.c.GetFloat64("emoji.maxsize", 128.0)
ok, fname, _, err := p.isKnownEmojy(name) ok, fname, _, err := p.isKnownEmojy(name)
if !ok || err != nil { if !ok || err != nil {
u := p.c.Get("baseurl", "") u := p.c.Get("baseurl", "")
u = u + "/emojy" u = u + "/emojy"
return fmt.Errorf("error getting emojy, the known emojy list can be found at: %s", u) return fmt.Errorf("error getting emojy, the known emojy list can be found at: %s", u)
} }
f, err := os.Open(fname) i, err := gg.LoadImage(fname)
if err != nil { if err != nil {
return err return err
} }
img, _, err := image.Decode(f) ctx := gg.NewContextForImage(i)
if err != nil {
return err
}
return p.UploadEmojyImage(c, name, img)
}
func imageToRGBA(src image.Image) *image.RGBA {
// No conversion needed if image is an *image.RGBA.
if dst, ok := src.(*image.RGBA); ok {
return dst
}
// Use the image/draw package to convert to *image.RGBA.
b := src.Bounds()
dst := image.NewRGBA(image.Rect(0, 0, b.Dx(), b.Dy()))
draw.Draw(dst, dst.Bounds(), src, b.Min, draw.Src)
return dst
}
func (p *EmojyPlugin) UploadEmojyImage(c bot.Connector, name string, data image.Image) error {
maxEmojySz := p.c.GetFloat64("emoji.maxsize", 128.0)
ctx := gg.NewContextForRGBA(imageToRGBA(data))
max := math.Max(float64(ctx.Width()), float64(ctx.Height())) max := math.Max(float64(ctx.Width()), float64(ctx.Height()))
ctx.Scale(maxEmojySz/max, maxEmojySz/max) ctx.Scale(maxEmojySz/max, maxEmojySz/max)
w := bytes.NewBuffer([]byte{}) w := bytes.NewBuffer([]byte{})
err := ctx.EncodePNG(w) err = ctx.EncodePNG(w)
if err != nil { if err != nil {
return err return err
} }
@ -300,7 +261,7 @@ func (p *EmojyPlugin) UploadEmojyImage(c bot.Connector, name string, data image.
return nil return nil
} }
func SanitizeName(name string) string { func sanitizeName(name string) string {
name = strings.ReplaceAll(name, "-", "_") name = strings.ReplaceAll(name, "-", "_")
nameLen := len(name) nameLen := len(name)
if nameLen > maxLen { if nameLen > maxLen {