diff --git a/EsefexApi/.dockerignore b/EsefexApi/.dockerignore index a462950..f92f8d4 100644 --- a/EsefexApi/.dockerignore +++ b/EsefexApi/.dockerignore @@ -1,4 +1,6 @@ /sounds /testsounds /data -/database \ No newline at end of file +/database + +.env \ No newline at end of file diff --git a/EsefexApi/bot/commands/list.go b/EsefexApi/bot/commands/list.go index 51d700f..31d3434 100644 --- a/EsefexApi/bot/commands/list.go +++ b/EsefexApi/bot/commands/list.go @@ -60,7 +60,7 @@ func fmtMetaList(metas []sounddb.SoundMeta) string { // log.Printf("fmtMetaList: %v", metas) var str string for _, meta := range metas { - str += fmt.Sprintf("- %s `%s`\n", meta.Name, meta.SoundID) + str += fmt.Sprintf("- %s %s `%s`\n", meta.Icon.String(), meta.Name, meta.SoundID) } // log.Println(str) diff --git a/EsefexApi/bot/commands/upload.go b/EsefexApi/bot/commands/upload.go index 654dcc1..0dc730b 100644 --- a/EsefexApi/bot/commands/upload.go +++ b/EsefexApi/bot/commands/upload.go @@ -1,6 +1,7 @@ package commands import ( + "esefexapi/sounddb" "esefexapi/util" "fmt" "log" @@ -38,8 +39,11 @@ var ( func (c *CommandHandlers) Upload(s *discordgo.Session, i *discordgo.InteractionCreate) (*discordgo.InteractionResponse, error) { options := OptionsMap(i) - icon := options["icon"] - iconURL := util.ExtractIconUrl(icon) + iconOption := options["icon"] + icon, err := sounddb.ExtractIcon(fmt.Sprint(iconOption.Value)) + if err != nil { + return nil, err + } soundFile := options["sound-file"] soundFileUrl := i.ApplicationCommandData().Resolved.Attachments[fmt.Sprint(soundFile.Value)].URL @@ -49,13 +53,16 @@ func (c *CommandHandlers) Upload(s *discordgo.Session, i *discordgo.InteractionC return nil, err } - c.db.AddSound(i.GuildID, fmt.Sprint(options["name"].Value), iconURL, pcm) + uid, err := c.db.AddSound(i.GuildID, fmt.Sprint(options["name"].Value), icon, pcm) + if err != nil { + return nil, err + } - log.Printf("Uploaded sound effect %v to server %v", options["name"].Value, i.GuildID) + log.Printf("Uploaded sound effect %v to server %v", uid.SoundID, i.GuildID) return &discordgo.InteractionResponse{ Type: discordgo.InteractionResponseChannelMessageWithSource, Data: &discordgo.InteractionResponseData{ - Content: "Uploaded sound effect", + Content: fmt.Sprintf("Uploaded sound effect %s %s", uid.SoundID, icon.Name), }, }, nil } diff --git a/EsefexApi/cmd/emoji_testing/emoji_testing.go b/EsefexApi/cmd/emoji_testing/emoji_testing.go new file mode 100644 index 0000000..3a149e8 --- /dev/null +++ b/EsefexApi/cmd/emoji_testing/emoji_testing.go @@ -0,0 +1,17 @@ +package main + +import ( + "esefexapi/sounddb" + "fmt" +) + +func main() { + text := "<:emoji:630819109726191617>๐Ÿ€„๐Ÿ†˜๐ŸงŒ๐Ÿคก๐Ÿ†˜" + + icon, err := sounddb.ExtractIcon(text) + if err != nil { + panic(err) + } + + fmt.Println(icon) +} diff --git a/EsefexApi/docker-compose.yml b/EsefexApi/docker-compose.yml index ed8eb9c..4e298ca 100644 --- a/EsefexApi/docker-compose.yml +++ b/EsefexApi/docker-compose.yml @@ -1,6 +1,8 @@ services: api: image: jokil/esefexapi:latest + env_file: + - .env.github ports: - "8080:8080" volumes: diff --git a/EsefexApi/go.mod b/EsefexApi/go.mod index 7bfd925..4548212 100644 --- a/EsefexApi/go.mod +++ b/EsefexApi/go.mod @@ -13,11 +13,13 @@ require github.com/pelletier/go-toml v1.9.5 require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect + golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) require ( github.com/gorilla/websocket v1.4.2 // indirect + github.com/samber/lo v1.39.0 github.com/stretchr/testify v1.8.4 golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b // indirect golang.org/x/sys v0.0.0-20211019181941-9d821ace8654 // indirect diff --git a/EsefexApi/go.sum b/EsefexApi/go.sum index e04e373..8aa496d 100644 --- a/EsefexApi/go.sum +++ b/EsefexApi/go.sum @@ -12,10 +12,14 @@ github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3v github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/samber/lo v1.39.0 h1:4gTz1wUhNYLhFSKl6O+8peW0v2F4BCY034GRpU9WnuA= +github.com/samber/lo v1.39.0/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b h1:7mWr3k41Qtv8XlltBkDkl8LoP3mpSgBW8BUoxtEdbXg= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17 h1:3MTrJm4PyNL9NBqvYDSj3DHl46qQakyfqfWo4jgfaEM= +golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20211019181941-9d821ace8654 h1:id054HUawV2/6IGm2IV8KZQjqtwAOo2CYlOToYqa0d0= diff --git a/EsefexApi/sounddb/apimockdb/apimockdb.go b/EsefexApi/sounddb/apimockdb/apimockdb.go index 3ec7861..3406b48 100644 --- a/EsefexApi/sounddb/apimockdb/apimockdb.go +++ b/EsefexApi/sounddb/apimockdb/apimockdb.go @@ -8,13 +8,21 @@ var mockData = map[string]map[string]sounddb.SoundMeta{ SoundID: "sound1", ServerID: "server1", Name: "sound1Name", - Icon: "icon1", + Icon: sounddb.Icon{ + Name: "icon1", + ID: "icon1ID", + Url: "https://icon1Url.webp", + }, }, "sound2": { SoundID: "sound2", ServerID: "server1", Name: "sound2Name", - Icon: "icon2", + Icon: sounddb.Icon{ + Name: "icon2", + ID: "icon2ID", + Url: "https://icon2Url.webp", + }, }, }, "server2": { @@ -22,13 +30,21 @@ var mockData = map[string]map[string]sounddb.SoundMeta{ SoundID: "sound3", ServerID: "server2", Name: "sound3Name", - Icon: "icon3", + Icon: sounddb.Icon{ + Name: "icon3", + ID: "icon3ID", + Url: "https://icon3Url.webp", + }, }, "sound4": { SoundID: "sound4", ServerID: "server2", Name: "sound4Name", - Icon: "icon4", + Icon: sounddb.Icon{ + Name: "icon4", + ID: "icon4ID", + Url: "https://icon4Url.webp", + }, }, }, } @@ -43,7 +59,7 @@ func NewApiMockDB() *ApiMockDB { } // AddSound implements sounddb.ISoundDB. -func (*ApiMockDB) AddSound(serverID string, name string, icon string, pcm []int16) (sounddb.SoundUID, error) { +func (*ApiMockDB) AddSound(serverID string, name string, icon sounddb.Icon, pcm []int16) (sounddb.SoundUID, error) { panic("unimplemented") } diff --git a/EsefexApi/sounddb/db.go b/EsefexApi/sounddb/db.go index 72138d6..b7b6cfe 100644 --- a/EsefexApi/sounddb/db.go +++ b/EsefexApi/sounddb/db.go @@ -1,7 +1,7 @@ package sounddb type ISoundDB interface { - AddSound(serverID string, name string, icon string, pcm []int16) (SoundUID, error) + AddSound(serverID string, name string, icon Icon, pcm []int16) (SoundUID, error) DeleteSound(uid SoundUID) error GetSoundMeta(uid SoundUID) (SoundMeta, error) GetSoundPcm(uid SoundUID) ([]int16, error) @@ -19,5 +19,5 @@ type SoundMeta struct { SoundID string `json:"id"` ServerID string `json:"serverId"` Name string `json:"name"` - Icon string `json:"icon"` + Icon Icon `json:"icon"` } diff --git a/EsefexApi/sounddb/dbcache/dbcache.go b/EsefexApi/sounddb/dbcache/dbcache.go index 71884dc..8ee1305 100644 --- a/EsefexApi/sounddb/dbcache/dbcache.go +++ b/EsefexApi/sounddb/dbcache/dbcache.go @@ -31,7 +31,7 @@ func NewDBCache(db sounddb.ISoundDB) *DBCache { } // AddSound implements db.SoundDB. -func (c *DBCache) AddSound(serverID string, name string, icon string, pcm []int16) (sounddb.SoundUID, error) { +func (c *DBCache) AddSound(serverID string, name string, icon sounddb.Icon, pcm []int16) (sounddb.SoundUID, error) { c.rw.Lock() defer c.rw.Unlock() diff --git a/EsefexApi/sounddb/filedb/addsound.go b/EsefexApi/sounddb/filedb/addsound.go index 966d3e2..815ddd5 100644 --- a/EsefexApi/sounddb/filedb/addsound.go +++ b/EsefexApi/sounddb/filedb/addsound.go @@ -10,7 +10,7 @@ import ( ) // AddSound implements sounddb.SoundDB. -func (f *FileDB) AddSound(serverID string, name string, iconUrl string, pcm []int16) (sounddb.SoundUID, error) { +func (f *FileDB) AddSound(serverID string, name string, icon sounddb.Icon, pcm []int16) (sounddb.SoundUID, error) { sid, err := f.generateSoundID(serverID) if err != nil { return sounddb.SoundUID{}, err @@ -20,7 +20,7 @@ func (f *FileDB) AddSound(serverID string, name string, iconUrl string, pcm []in SoundID: sid, ServerID: serverID, Name: name, - Icon: iconUrl, + Icon: icon, } // Make sure the db folder exists diff --git a/EsefexApi/sounddb/filedb/filedb_test.go b/EsefexApi/sounddb/filedb/filedb_test.go index b93866c..9d0eec7 100644 --- a/EsefexApi/sounddb/filedb/filedb_test.go +++ b/EsefexApi/sounddb/filedb/filedb_test.go @@ -14,7 +14,12 @@ import ( func TestFileDB(t *testing.T) { log.SetFlags(log.LstdFlags | log.Lshortfile) - iconUrl := "https://github.com/Cinnazeyy/Esefex/raw/main/EsefexApi/test/staticfiles/icon.webp" + icon := sounddb.Icon{ + Name: "icon1", + ID: "icon1", + Url: "https://raw.githubusercontent.com/EsefexBot/Esefex/main/EsefexApi/test/staticfiles/icon.webp", + } + serverID := "server1" soundName := "sound1" soundPcm := []int16{115, 117, 115} @@ -24,7 +29,7 @@ func TestFileDB(t *testing.T) { assert.Nil(t, err) // Test that we can add a sound - uid, err := db.AddSound(serverID, soundName, iconUrl, soundPcm) + uid, err := db.AddSound(serverID, soundName, icon, soundPcm) assert.Nil(t, err) _, err = os.Stat(fmt.Sprintf("%s/%s/%s_meta.json", location, serverID, uid.SoundID)) @@ -44,7 +49,7 @@ func TestFileDB(t *testing.T) { SoundID: uid.SoundID, ServerID: serverID, Name: soundName, - Icon: iconUrl, + Icon: icon, }) // Test that we can get the sound pcm diff --git a/EsefexApi/sounddb/icon.go b/EsefexApi/sounddb/icon.go new file mode 100644 index 0000000..cc6e2f5 --- /dev/null +++ b/EsefexApi/sounddb/icon.go @@ -0,0 +1,61 @@ +package sounddb + +import ( + "esefexapi/util" + "fmt" + "regexp" +) + +type Icon struct { + RegularEmoji bool `json:"regularEmoji"` + Name string `json:"name"` + ID string `json:"id"` + Url string `json:"url"` +} + +func NewCustomIcon(name string, id string) Icon { + return Icon{ + RegularEmoji: false, + Name: name, + ID: id, + Url: fmt.Sprintf("https://cdn.discordapp.com/emojis/%s.webp?quality=lossless", id), + } +} + +func NewEmojiIcon(emoji string) Icon { + return Icon{ + RegularEmoji: true, + Name: emoji, + Url: util.GetEmojiURL(emoji), + } +} + +func (i *Icon) String() string { + if i.RegularEmoji { + return i.Name + } + return fmt.Sprintf("<:%s:%s>", i.Name, i.ID) +} + +var iconRegex string = `<:([^:]+):(\d+)>` +var r *regexp.Regexp = regexp.MustCompile(fmt.Sprintf(`%s|(%s)`, iconRegex, util.EmojiRegex)) + +func ExtractIcon(str string) (Icon, error) { + m := r.FindStringSubmatch(str) + if m == nil { + return Icon{}, fmt.Errorf("invalid icon, no match") + } + if len(m) != 4 { + return Icon{}, fmt.Errorf("invalid icon, len(m) != 4") + } + + if m[1] != "" && m[2] != "" { + return NewCustomIcon(m[1], m[2]), nil + } + + if m[3] != "" { + return NewEmojiIcon(m[3]), nil + } + + return Icon{}, fmt.Errorf("invalid icon") +} diff --git a/EsefexApi/sounddb/sounddb_test.go b/EsefexApi/sounddb/sounddb_test.go new file mode 100644 index 0000000..9c7c38b --- /dev/null +++ b/EsefexApi/sounddb/sounddb_test.go @@ -0,0 +1,66 @@ +package sounddb + +import ( + "github.com/stretchr/testify/assert" + "testing" +) + +func ExtractIconTest(t *testing.T) { + text := "<:emoji:630819109726191617>๐Ÿ€„๐Ÿ†˜๐ŸงŒ๐Ÿคก๐Ÿ†˜" + icon, err := ExtractIcon(text) + assert.Nil(t, err) + assert.Equal(t, Icon{ + RegularEmoji: false, + Name: "emoji", + ID: "630819109726191617", + Url: "https://cdn.discordapp.com/emojis/630819109726191617.webp?quality=lossless", + }, icon) + + text = "๐Ÿ‘จโ€๐Ÿ‘จโ€๐Ÿ‘งโ€๐Ÿ‘ฆ๐Ÿ€„๐Ÿ†˜๐ŸงŒ๐Ÿคก๐Ÿ†˜" + icon, err = ExtractIcon(text) + assert.Nil(t, err) + assert.Equal(t, Icon{ + RegularEmoji: true, + Name: "๐Ÿ‘จโ€๐Ÿ‘จโ€๐Ÿ‘งโ€๐Ÿ‘ฆ", + Url: "https://raw.githubusercontent.com/twitter/twemoji/master/assets/svg/1f468-200d-1f468-200d-1f467-200d-1f466.svg", + }, icon) + + text = "<:emoji:630819109726191617>" + icon, err = ExtractIcon(text) + assert.Nil(t, err) + assert.Equal(t, Icon{ + RegularEmoji: false, + Name: "emoji", + ID: "630819109726191617", + Url: "https://cdn.discordapp.com/emojis/630819109726191617.webp?quality=lossless", + }, icon) + + text = "asdasc<:emoji:630819109726191617>asdasc" + icon, err = ExtractIcon(text) + assert.Nil(t, err) + assert.Equal(t, Icon{ + RegularEmoji: false, + Name: "emoji", + ID: "630819109726191617", + Url: "https://cdn.discordapp.com/emojis/630819109726191617.webp?quality=lossless", + }, icon) + + text = "asdasc<:emoji1:111>asdasc<:emoji2:222>asdasc" + icon, err = ExtractIcon(text) + assert.Nil(t, err) + assert.Equal(t, Icon{ + RegularEmoji: false, + Name: "emoji1", + ID: "111", + Url: "https://cdn.discordapp.com/emojis/111.webp?quality=lossless", + }, icon) + + text = "asdas<><