mirror of https://github.com/velour/catbase.git
Compare commits
3 Commits
97329eea26
...
b027de2f27
Author | SHA1 | Date |
---|---|---|
dependabot[bot] | b027de2f27 | |
Chris Sexton | e93b6d07ab | |
Chris Sexton | 866b947f42 |
12
go.mod
12
go.mod
|
@ -11,6 +11,7 @@ require (
|
|||
github.com/cenkalti/backoff/v4 v4.1.3
|
||||
github.com/chrissexton/leftpad v0.0.0-20181207133115-1e93189d2fff
|
||||
github.com/chrissexton/sentiment v0.0.0-20190927141846-d69c422ba035
|
||||
github.com/disintegration/imageorient v0.0.0-20180920195336-8147d86e83ec
|
||||
github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90
|
||||
github.com/forPelevin/gomoji v1.1.6
|
||||
github.com/gabriel-vasile/mimetype v1.4.1
|
||||
|
@ -18,7 +19,7 @@ require (
|
|||
github.com/go-chi/httprate v0.7.0
|
||||
github.com/gocolly/colly v1.2.0
|
||||
github.com/google/uuid v1.3.0
|
||||
github.com/itchyny/gojq v0.12.8
|
||||
github.com/itchyny/gojq v0.12.9
|
||||
github.com/james-bowman/nlp v0.0.0-20191016091239-d9dbfaff30c6
|
||||
github.com/jmoiron/sqlx v1.3.5
|
||||
github.com/kevinburke/twilio-go v0.0.0-20200424172635-4f0b2357b852
|
||||
|
@ -46,6 +47,7 @@ require (
|
|||
github.com/azr/backoff v0.0.0-20160115115103-53511d3c7330 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.1.2 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/disintegration/gift v1.1.2 // indirect
|
||||
github.com/dustin/go-jsonpointer v0.0.0-20160814072949-ba0abeacc3dc // indirect
|
||||
github.com/dustin/gojson v0.0.0-20160307161227-2e71ec9dd5ad // indirect
|
||||
github.com/garyburd/go-oauth v0.0.0-20180319155456-bca2e7f09a17 // indirect
|
||||
|
@ -58,7 +60,7 @@ require (
|
|||
github.com/gonum/internal v0.0.0-20181124074243-f884aa714029 // indirect
|
||||
github.com/gorilla/websocket v1.5.0 // indirect
|
||||
github.com/inconshreveable/log15 v0.0.0-20200109203555-b30bc20e4fd1 // indirect
|
||||
github.com/itchyny/timefmt-go v0.1.3 // indirect
|
||||
github.com/itchyny/timefmt-go v0.1.4 // indirect
|
||||
github.com/james-bowman/sparse v0.0.0-20190423065201-80c6877364c7 // indirect
|
||||
github.com/json-iterator/go v1.1.10 // indirect
|
||||
github.com/kennygrant/sanitize v1.2.4 // indirect
|
||||
|
@ -66,7 +68,7 @@ require (
|
|||
github.com/kevinburke/go.uuid v1.2.0 // indirect
|
||||
github.com/kevinburke/rest v0.0.0-20200429221318-0d2892b400f8 // indirect
|
||||
github.com/mattn/go-colorable v0.1.12 // indirect
|
||||
github.com/mattn/go-isatty v0.0.14 // indirect
|
||||
github.com/mattn/go-isatty v0.0.16 // indirect
|
||||
github.com/mmcdole/goxpp v0.0.0-20181012175147-0068e33feabf // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 // indirect
|
||||
|
@ -82,9 +84,9 @@ require (
|
|||
github.com/ttacon/libphonenumber v1.1.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20191014171548-69215a2ee97e // indirect
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b // indirect
|
||||
golang.org/x/net v0.0.0-20220909164309-bea034e7d591 // indirect
|
||||
golang.org/x/net v0.0.0-20221002022538-bcab6841153b // indirect
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
|
||||
golang.org/x/sys v0.0.0-20220915200043-7b5979e65e41 // indirect
|
||||
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec // indirect
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
gonum.org/v1/gonum v0.6.0 // indirect
|
||||
google.golang.org/appengine v1.6.5 // indirect
|
||||
|
|
27
go.sum
27
go.sum
|
@ -44,6 +44,10 @@ github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:ma
|
|||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/disintegration/gift v1.1.2 h1:9ZyHJr+kPamiH10FX3Pynt1AxFUob812bU9Wt4GMzhs=
|
||||
github.com/disintegration/gift v1.1.2/go.mod h1:Jh2i7f7Q2BM7Ezno3PhfezbR1xpUg9dUg3/RlKGr4HI=
|
||||
github.com/disintegration/imageorient v0.0.0-20180920195336-8147d86e83ec h1:YrB6aVr9touOt75I9O1SiancmR2GMg45U9UYf0gtgWg=
|
||||
github.com/disintegration/imageorient v0.0.0-20180920195336-8147d86e83ec/go.mod h1:K0KBFIr1gWu/C1Gp10nFAcAE4hsB7JxE6OgLijrJ8Sk=
|
||||
github.com/dustin/go-jsonpointer v0.0.0-20160814072949-ba0abeacc3dc h1:tP7tkU+vIsEOKiK+l/NSLN4uUtkyuxc6hgYpQeCWAeI=
|
||||
github.com/dustin/go-jsonpointer v0.0.0-20160814072949-ba0abeacc3dc/go.mod h1:ORH5Qp2bskd9NzSfKqAF7tKfONsEkCarTE5ESr/RVBw=
|
||||
github.com/dustin/gojson v0.0.0-20160307161227-2e71ec9dd5ad h1:Qk76DOWdOp+GlyDKBAG3Klr9cn7N+LcYc82AZ2S7+cA=
|
||||
|
@ -82,7 +86,6 @@ github.com/gonum/floats v0.0.0-20181209220543-c233463c7e82 h1:EvokxLQsaaQjcWVWSV
|
|||
github.com/gonum/floats v0.0.0-20181209220543-c233463c7e82/go.mod h1:PxC8OnwL11+aosOB5+iEPoV3picfs8tUpkVd0pDo+Kg=
|
||||
github.com/gonum/internal v0.0.0-20181124074243-f884aa714029 h1:8jtTdc+Nfj9AR+0soOeia9UZSvYBvETVHZrugUowJ7M=
|
||||
github.com/gonum/internal v0.0.0-20181124074243-f884aa714029/go.mod h1:Pu4dmpkhSyOzRwuXkOgAvijx4o+4YMUJJo9OvPYMkks=
|
||||
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o=
|
||||
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
|
@ -93,10 +96,10 @@ github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWm
|
|||
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/inconshreveable/log15 v0.0.0-20200109203555-b30bc20e4fd1 h1:KUDFlmBg2buRWNzIcwLlKvfcnujcHQRQ1As1LoaCLAM=
|
||||
github.com/inconshreveable/log15 v0.0.0-20200109203555-b30bc20e4fd1/go.mod h1:cOaXtrgN4ScfRrD9Bre7U1thNq5RtJ8ZoP4iXVGRj6o=
|
||||
github.com/itchyny/gojq v0.12.8 h1:Zxcwq8w4IeR8JJYEtoG2MWJZUv0RGY6QqJcO1cqV8+A=
|
||||
github.com/itchyny/gojq v0.12.8/go.mod h1:gE2kZ9fVRU0+JAksaTzjIlgnCa2akU+a1V0WXgJQN5c=
|
||||
github.com/itchyny/timefmt-go v0.1.3 h1:7M3LGVDsqcd0VZH2U+x393obrzZisp7C0uEe921iRkU=
|
||||
github.com/itchyny/timefmt-go v0.1.3/go.mod h1:0osSSCQSASBJMsIZnhAaF1C2fCBTJZXrnj37mG8/c+A=
|
||||
github.com/itchyny/gojq v0.12.9 h1:biKpbKwMxVYhCU1d6mR7qMr3f0Hn9F5k5YykCVb3gmM=
|
||||
github.com/itchyny/gojq v0.12.9/go.mod h1:T4Ip7AETUXeGpD+436m+UEl3m3tokRgajd5pRfsR5oE=
|
||||
github.com/itchyny/timefmt-go v0.1.4 h1:hFEfWVdwsEi+CY8xY2FtgWHGQaBaC3JeHd+cve0ynVM=
|
||||
github.com/itchyny/timefmt-go v0.1.4/go.mod h1:nEP7L+2YmAbT2kZ2HfSs1d8Xtw9LY8D2stDBckWakZ8=
|
||||
github.com/james-bowman/nlp v0.0.0-20191016091239-d9dbfaff30c6 h1:k8+n5sfvxlixRNVkbelPGzEYjbGIKaBnRzRlx2NCtYA=
|
||||
github.com/james-bowman/nlp v0.0.0-20191016091239-d9dbfaff30c6/go.mod h1:kixuaexEqWB+mHZNysgnb6mqgGIT25WvD1/tFRRt0J0=
|
||||
github.com/james-bowman/sparse v0.0.0-20190423065201-80c6877364c7 h1:ph/BDQQDL41apnHSN48I5GyNOQXXAlc79HwGqDSXCss=
|
||||
|
@ -120,9 +123,9 @@ github.com/lib/pq v1.2.0 h1:LXpIM/LZ5xGFhOpXAQUIMM1HdyqzVYM13zNdjCEEcA0=
|
|||
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40=
|
||||
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
|
||||
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
|
||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
|
||||
github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U=
|
||||
github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
|
@ -143,7 +146,6 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
|||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
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/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/rivo/uniseg v0.3.4 h1:3Z3Eu6FGHZWSfNKJTOUiPatWwfc7DzJRU04jFUqJODw=
|
||||
github.com/rivo/uniseg v0.3.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||
github.com/robertkrimen/otto v0.0.0-20180617131154-15f95af6e78d h1:1VUlQbCfkoSGv7qP7Y+ro3ap1P1pPZxgdGVqiTVy5C4=
|
||||
|
@ -204,8 +206,8 @@ golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLL
|
|||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.0.0-20220909164309-bea034e7d591 h1:D0B/7al0LLrVC8aWF4+oxpv/m8bc7ViFfVS8/gXGdqI=
|
||||
golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
||||
golang.org/x/net v0.0.0-20221002022538-bcab6841153b h1:6e93nYa3hNqAvLr0pD4PN1fFS+gKzp2zAXqrnTCstqU=
|
||||
golang.org/x/net v0.0.0-20221002022538-bcab6841153b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
|
@ -218,8 +220,9 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220915200043-7b5979e65e41 h1:ohgcoMbSofXygzo6AD2I1kz3BFmW1QArPYTtwEM3UXc=
|
||||
golang.org/x/sys v0.0.0-20220915200043-7b5979e65e41/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec h1:BkDtF2Ih9xZ7le9ndzTA7KJow28VbQW3odyk/8drmuI=
|
||||
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
|
|
2
main.go
2
main.go
|
@ -6,6 +6,7 @@ import (
|
|||
"flag"
|
||||
"github.com/velour/catbase/plugins/pagecomment"
|
||||
"github.com/velour/catbase/plugins/talker"
|
||||
"github.com/velour/catbase/plugins/tappd"
|
||||
"github.com/velour/catbase/plugins/topic"
|
||||
"io"
|
||||
"math/rand"
|
||||
|
@ -144,6 +145,7 @@ func main() {
|
|||
b.AddPlugin(leftpad.New(b))
|
||||
b.AddPlugin(dice.New(b))
|
||||
b.AddPlugin(picker.New(b))
|
||||
b.AddPlugin(tappd.New(b))
|
||||
b.AddPlugin(beers.New(b))
|
||||
b.AddPlugin(remember.New(b))
|
||||
b.AddPlugin(your.New(b))
|
||||
|
|
|
@ -306,7 +306,15 @@ var defaultFormats = map[string]string{
|
|||
"raptor": "https://imgflip.com/s/meme/Philosoraptor.jpg",
|
||||
}
|
||||
|
||||
func (p *MemePlugin) findFontSize(config []memeText, fontLocation string, w, h int, sizes []float64) float64 {
|
||||
func FindFontSizeConfigs(configs []memeText, fontLocation string, w, h int, sizes []float64) float64 {
|
||||
texts := []string{}
|
||||
for _, c := range configs {
|
||||
texts = append(texts, c.Text)
|
||||
}
|
||||
return FindFontSize(texts, fontLocation, w, h, sizes)
|
||||
}
|
||||
|
||||
func FindFontSize(config []string, fontLocation string, w, h int, sizes []float64) float64 {
|
||||
fontSize := 12.0
|
||||
|
||||
m := gg.NewContext(w, h)
|
||||
|
@ -320,9 +328,9 @@ func (p *MemePlugin) findFontSize(config []memeText, fontLocation string, w, h i
|
|||
return fontSize
|
||||
}
|
||||
|
||||
w, _ := m.MeasureString(s.Text)
|
||||
w, _ := m.MeasureString(s)
|
||||
if w > longestW {
|
||||
longestStr = s.Text
|
||||
longestStr = s
|
||||
longestW = w
|
||||
}
|
||||
}
|
||||
|
@ -449,6 +457,7 @@ func (p *MemePlugin) genMeme(spec specification) ([]byte, error) {
|
|||
// Apply black stroke
|
||||
m.SetHexColor("#000")
|
||||
strokeSize := 6
|
||||
fontSize := FindFontSizeConfigs(spec.Configs, defaultFont, w, h, fontSizes)
|
||||
for dy := -strokeSize; dy <= strokeSize; dy++ {
|
||||
for dx := -strokeSize; dx <= strokeSize; dx++ {
|
||||
// give it rounded corners
|
||||
|
@ -460,7 +469,6 @@ func (p *MemePlugin) genMeme(spec specification) ([]byte, error) {
|
|||
if fontLocation == "" {
|
||||
fontLocation = defaultFont
|
||||
}
|
||||
fontSize := p.findFontSize(spec.Configs, fontLocation, w, h, fontSizes)
|
||||
m.LoadFontFace(fontLocation, fontSize)
|
||||
x := float64(w)*c.XPerc + float64(dx)
|
||||
y := float64(h)*c.YPerc + float64(dy)
|
||||
|
@ -476,7 +484,6 @@ func (p *MemePlugin) genMeme(spec specification) ([]byte, error) {
|
|||
if fontLocation == "" {
|
||||
fontLocation = defaultFont
|
||||
}
|
||||
fontSize := p.findFontSize(spec.Configs, fontLocation, w, h, fontSizes)
|
||||
m.LoadFontFace(fontLocation, fontSize)
|
||||
x := float64(w) * c.XPerc
|
||||
y := float64(h) * c.YPerc
|
||||
|
|
|
@ -0,0 +1,145 @@
|
|||
package tappd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"github.com/disintegration/imageorient"
|
||||
"github.com/fogleman/gg"
|
||||
"github.com/nfnt/resize"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/velour/catbase/plugins/meme"
|
||||
"image"
|
||||
"image/png"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"path"
|
||||
)
|
||||
|
||||
func (p *Tappd) getImage(url string) (image.Image, error) {
|
||||
resp, err := http.Get(url)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
img, _, err := imageorient.Decode(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
r := img.Bounds()
|
||||
w := r.Dx()
|
||||
h := r.Dy()
|
||||
|
||||
maxSz := p.c.GetFloat64("maxImgSz", 750.0)
|
||||
|
||||
if w > h {
|
||||
scale := maxSz / float64(w)
|
||||
w = int(float64(w) * scale)
|
||||
h = int(float64(h) * scale)
|
||||
} else {
|
||||
scale := maxSz / float64(h)
|
||||
w = int(float64(w) * scale)
|
||||
h = int(float64(h) * scale)
|
||||
}
|
||||
|
||||
log.Debug().Msgf("trynig to resize to %v, %v", w, h)
|
||||
img = resize.Resize(uint(w), uint(h), img, resize.Lanczos3)
|
||||
r = img.Bounds()
|
||||
w = r.Dx()
|
||||
h = r.Dy()
|
||||
log.Debug().Msgf("resized to %v, %v", w, h)
|
||||
|
||||
return img, nil
|
||||
}
|
||||
|
||||
type textSpec struct {
|
||||
text string
|
||||
// percentage location of text center
|
||||
x float64
|
||||
y float64
|
||||
}
|
||||
|
||||
func defaultSpec() textSpec {
|
||||
return textSpec{
|
||||
x: 0.5,
|
||||
y: 0.9,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Tappd) overlay(img image.Image, texts []textSpec) ([]byte, error) {
|
||||
font := p.c.Get("meme.font", "impact.ttf")
|
||||
fontSizes := []float64{48, 36, 24, 16, 12}
|
||||
r := img.Bounds()
|
||||
w := r.Dx()
|
||||
h := r.Dy()
|
||||
|
||||
txts := []string{}
|
||||
for _, t := range texts {
|
||||
txts = append(txts, t.text)
|
||||
}
|
||||
|
||||
fontSize := meme.FindFontSize(txts, font, w, h, fontSizes)
|
||||
|
||||
m := gg.NewContext(w, h)
|
||||
m.DrawImage(img, 0, 0)
|
||||
for _, spec := range texts {
|
||||
// write some stuff on the image here
|
||||
if err := m.LoadFontFace(font, fontSize); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Apply black stroke
|
||||
m.SetHexColor("#000")
|
||||
strokeSize := 6
|
||||
for dy := -strokeSize; dy <= strokeSize; dy++ {
|
||||
for dx := -strokeSize; dx <= strokeSize; dx++ {
|
||||
// give it rounded corners
|
||||
if dx*dx+dy*dy >= strokeSize*strokeSize {
|
||||
continue
|
||||
}
|
||||
x := float64(w)*spec.x + float64(dx)
|
||||
y := float64(h)*spec.y + float64(dy)
|
||||
m.DrawStringAnchored(spec.text, x, y, 0.5, 0.5)
|
||||
}
|
||||
}
|
||||
|
||||
m.SetHexColor("#FFF")
|
||||
x := float64(w) * spec.x
|
||||
y := float64(h) * spec.y
|
||||
m.DrawStringAnchored(spec.text, x, y, 0.5, 0.5)
|
||||
}
|
||||
i := bytes.Buffer{}
|
||||
if err := png.Encode(&i, m.Image()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return i.Bytes(), nil
|
||||
}
|
||||
|
||||
func (p *Tappd) getAndOverlay(id, srcURL string, texts []textSpec) (imageInfo, error) {
|
||||
baseURL := p.c.Get("BaseURL", ``)
|
||||
u, _ := url.Parse(baseURL)
|
||||
u.Path = path.Join(u.Path, "tappd", id)
|
||||
img, err := p.getImage(srcURL)
|
||||
if err != nil {
|
||||
return imageInfo{}, err
|
||||
}
|
||||
data, err := p.overlay(img, texts)
|
||||
if err != nil {
|
||||
return imageInfo{}, err
|
||||
}
|
||||
bounds := img.Bounds()
|
||||
info := imageInfo{
|
||||
ID: id,
|
||||
SrcURL: srcURL,
|
||||
BotURL: u.String(),
|
||||
Img: img,
|
||||
Repr: data,
|
||||
W: bounds.Dx(),
|
||||
H: bounds.Dy(),
|
||||
}
|
||||
p.imageMap[id] = info
|
||||
log.Debug().
|
||||
Interface("BotURL", info.BotURL).
|
||||
Str("ID", id).
|
||||
Msgf("here's some info")
|
||||
return info, nil
|
||||
}
|
|
@ -0,0 +1,176 @@
|
|||
package tappd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/bwmarrin/discordgo"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/velour/catbase/bot"
|
||||
"github.com/velour/catbase/config"
|
||||
"github.com/velour/catbase/connectors/discord"
|
||||
"image"
|
||||
"regexp"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Tappd struct {
|
||||
b bot.Bot
|
||||
c *config.Config
|
||||
imageMap map[string]imageInfo
|
||||
}
|
||||
|
||||
type imageInfo struct {
|
||||
ID string
|
||||
SrcURL string
|
||||
BotURL string
|
||||
Img image.Image
|
||||
Repr []byte
|
||||
W int
|
||||
H int
|
||||
}
|
||||
|
||||
func New(b bot.Bot) *Tappd {
|
||||
t := &Tappd{
|
||||
b: b,
|
||||
c: b.Config(),
|
||||
imageMap: make(map[string]imageInfo),
|
||||
}
|
||||
t.register()
|
||||
t.registerWeb()
|
||||
t.mkDB()
|
||||
return t
|
||||
}
|
||||
|
||||
func (p *Tappd) mkDB() error {
|
||||
db := p.b.DB()
|
||||
tx, err := db.Beginx()
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
_, err = tx.Exec(`create table if not exists tappd (
|
||||
id integer primary key autoincrement,
|
||||
who string,
|
||||
channel string,
|
||||
message string,
|
||||
ts datetime
|
||||
);`)
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
err = tx.Commit()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Tappd) log(who, channel, message string) error {
|
||||
db := p.b.DB()
|
||||
tx, err := db.Beginx()
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
_, err = tx.Exec(`insert into tappd (who, channel, message, ts) values (?, ?, ? ,?)`,
|
||||
who, channel, message, time.Now())
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
err = tx.Commit()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Tappd) registerDiscord(d *discord.Discord) {
|
||||
cmd := discordgo.ApplicationCommand{
|
||||
Name: "tap",
|
||||
Description: "tappd a beer in",
|
||||
Options: []*discordgo.ApplicationCommandOption{
|
||||
{
|
||||
Type: discordgo.ApplicationCommandOptionAttachment,
|
||||
Name: "image",
|
||||
Description: "Picture that beer, but on Discord",
|
||||
Required: true,
|
||||
},
|
||||
{
|
||||
Type: discordgo.ApplicationCommandOptionString,
|
||||
Name: "comment",
|
||||
Description: "Comment on that beer",
|
||||
Required: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
if err := d.RegisterSlashCmd(cmd, p.tap); err != nil {
|
||||
log.Error().Err(err).Msgf("could not register")
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Tappd) tap(s *discordgo.Session, i *discordgo.InteractionCreate) {
|
||||
who := i.Interaction.Member.Nick
|
||||
channel := i.Interaction.ChannelID
|
||||
msg := fmt.Sprintf("%s checked in: %s",
|
||||
i.Interaction.Member.Nick,
|
||||
i.ApplicationCommandData().Options[1].StringValue())
|
||||
attachID := i.ApplicationCommandData().Options[0].Value.(string)
|
||||
attach := i.ApplicationCommandData().Resolved.Attachments[attachID]
|
||||
spec := defaultSpec()
|
||||
spec.text = msg
|
||||
info, err := p.getAndOverlay(attachID, attach.URL, []textSpec{spec})
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msgf("error with interaction")
|
||||
err = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
|
||||
Type: discordgo.InteractionResponseChannelMessageWithSource,
|
||||
Data: &discordgo.InteractionResponseData{
|
||||
Content: "Error getting the image",
|
||||
Flags: discordgo.MessageFlagsEphemeral,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msgf("error with interaction")
|
||||
}
|
||||
return
|
||||
}
|
||||
embed := &discordgo.MessageEmbed{
|
||||
Description: msg,
|
||||
Image: &discordgo.MessageEmbedImage{
|
||||
URL: info.BotURL,
|
||||
Width: info.W,
|
||||
Height: info.H,
|
||||
},
|
||||
}
|
||||
err = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
|
||||
Type: discordgo.InteractionResponseChannelMessageWithSource,
|
||||
Data: &discordgo.InteractionResponseData{
|
||||
Embeds: []*discordgo.MessageEmbed{embed},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msgf("error with interaction")
|
||||
return
|
||||
}
|
||||
err = p.log(who, channel, msg)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msgf("error recording tap")
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Tappd) register() {
|
||||
ht := bot.HandlerTable{
|
||||
{
|
||||
Kind: bot.Startup, IsCmd: false,
|
||||
Regex: regexp.MustCompile(`.*`),
|
||||
Handler: func(r bot.Request) bool {
|
||||
switch conn := r.Conn.(type) {
|
||||
case *discord.Discord:
|
||||
p.registerDiscord(conn)
|
||||
}
|
||||
return false
|
||||
},
|
||||
},
|
||||
}
|
||||
p.b.RegisterTable(p, ht)
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
package tappd
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/rs/zerolog/log"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func (p *Tappd) registerWeb() {
|
||||
r := chi.NewRouter()
|
||||
r.HandleFunc("/", p.serveImage)
|
||||
p.b.RegisterWeb(r, "/tappd/{id}")
|
||||
}
|
||||
|
||||
func (p *Tappd) serveImage(w http.ResponseWriter, r *http.Request) {
|
||||
id := chi.URLParam(r, "id")
|
||||
imgData, ok := p.imageMap[id]
|
||||
log.Debug().
|
||||
Str("id", id).
|
||||
Str("SrcURL", imgData.SrcURL).
|
||||
Bool("ok", ok).
|
||||
Msgf("creating request")
|
||||
if !ok {
|
||||
w.WriteHeader(404)
|
||||
out, _ := json.Marshal(struct{ err string }{"could not find ID"})
|
||||
w.Write(out)
|
||||
return
|
||||
}
|
||||
w.Write(imgData.Repr)
|
||||
}
|
Loading…
Reference in New Issue