aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristine Dodrill <me@christine.website>2017-05-31 22:45:56 -0700
committerChristine Dodrill <me@christine.website>2017-05-31 22:45:56 -0700
commitf86e39c7bd447720b385d2da901694a30cfbdbe5 (patch)
tree375e82e8fac3750e43f5d5be3531e8f00ba13b9d
parent495864f18470b056a644da37f68f9cc447e74d1b (diff)
downloadx-f86e39c7bd447720b385d2da901694a30cfbdbe5.tar.xz
x-f86e39c7bd447720b385d2da901694a30cfbdbe5.zip
pbot: new primitive gif filter bot
-rw-r--r--tg/pbot/main.go139
-rw-r--r--tg/pbot/puush.go93
-rw-r--r--tg/pbot/vendor-log22
-rw-r--r--tg/pbot/vendor/github.com/Xe/uuid/dce.go84
-rw-r--r--tg/pbot/vendor/github.com/Xe/uuid/doc.go8
-rw-r--r--tg/pbot/vendor/github.com/Xe/uuid/hash.go53
-rw-r--r--tg/pbot/vendor/github.com/Xe/uuid/node.go101
-rw-r--r--tg/pbot/vendor/github.com/Xe/uuid/time.go132
-rw-r--r--tg/pbot/vendor/github.com/Xe/uuid/util.go43
-rw-r--r--tg/pbot/vendor/github.com/Xe/uuid/uuid.go163
-rw-r--r--tg/pbot/vendor/github.com/Xe/uuid/version1.go41
-rw-r--r--tg/pbot/vendor/github.com/Xe/uuid/version4.go25
-rw-r--r--tg/pbot/vendor/github.com/fogleman/gg/bezier.go59
-rw-r--r--tg/pbot/vendor/github.com/fogleman/gg/context.go795
-rw-r--r--tg/pbot/vendor/github.com/fogleman/gg/gradient.go202
-rw-r--r--tg/pbot/vendor/github.com/fogleman/gg/matrix.go88
-rw-r--r--tg/pbot/vendor/github.com/fogleman/gg/path.go140
-rw-r--r--tg/pbot/vendor/github.com/fogleman/gg/pattern.go123
-rw-r--r--tg/pbot/vendor/github.com/fogleman/gg/point.go25
-rw-r--r--tg/pbot/vendor/github.com/fogleman/gg/util.go117
-rw-r--r--tg/pbot/vendor/github.com/fogleman/gg/wrap.go58
-rw-r--r--tg/pbot/vendor/github.com/fogleman/primitive/primitive/color.go44
-rw-r--r--tg/pbot/vendor/github.com/fogleman/primitive/primitive/core.go124
-rw-r--r--tg/pbot/vendor/github.com/fogleman/primitive/primitive/ellipse.go179
-rw-r--r--tg/pbot/vendor/github.com/fogleman/primitive/primitive/heatmap.go59
-rw-r--r--tg/pbot/vendor/github.com/fogleman/primitive/primitive/log.go23
-rw-r--r--tg/pbot/vendor/github.com/fogleman/primitive/primitive/model.go174
-rw-r--r--tg/pbot/vendor/github.com/fogleman/primitive/primitive/optimize.go75
-rw-r--r--tg/pbot/vendor/github.com/fogleman/primitive/primitive/polygon.go111
-rw-r--r--tg/pbot/vendor/github.com/fogleman/primitive/primitive/quadratic.go100
-rw-r--r--tg/pbot/vendor/github.com/fogleman/primitive/primitive/raster.go46
-rw-r--r--tg/pbot/vendor/github.com/fogleman/primitive/primitive/rectangle.go198
-rw-r--r--tg/pbot/vendor/github.com/fogleman/primitive/primitive/scanline.go29
-rw-r--r--tg/pbot/vendor/github.com/fogleman/primitive/primitive/shape.go25
-rw-r--r--tg/pbot/vendor/github.com/fogleman/primitive/primitive/state.go48
-rw-r--r--tg/pbot/vendor/github.com/fogleman/primitive/primitive/triangle.go171
-rw-r--r--tg/pbot/vendor/github.com/fogleman/primitive/primitive/util.go195
-rw-r--r--tg/pbot/vendor/github.com/fogleman/primitive/primitive/worker.go108
-rw-r--r--tg/pbot/vendor/github.com/golang/freetype/raster/geom.go245
-rw-r--r--tg/pbot/vendor/github.com/golang/freetype/raster/paint.go287
-rw-r--r--tg/pbot/vendor/github.com/golang/freetype/raster/raster.go601
-rw-r--r--tg/pbot/vendor/github.com/golang/freetype/raster/stroke.go483
-rw-r--r--tg/pbot/vendor/github.com/golang/freetype/truetype/face.go507
-rw-r--r--tg/pbot/vendor/github.com/golang/freetype/truetype/glyph.go522
-rw-r--r--tg/pbot/vendor/github.com/golang/freetype/truetype/hint.go1770
-rw-r--r--tg/pbot/vendor/github.com/golang/freetype/truetype/opcodes.go289
-rw-r--r--tg/pbot/vendor/github.com/golang/freetype/truetype/truetype.go653
-rw-r--r--tg/pbot/vendor/github.com/hullerob/go.farbfeld/farbfeld.go96
-rw-r--r--tg/pbot/vendor/github.com/joho/godotenv/autoload/autoload.go15
-rw-r--r--tg/pbot/vendor/github.com/joho/godotenv/godotenv.go247
-rw-r--r--tg/pbot/vendor/github.com/technoweenie/multipartstreamer/multipartstreamer.go101
-rw-r--r--tg/pbot/vendor/golang.org/x/image/bmp/reader.go199
-rw-r--r--tg/pbot/vendor/golang.org/x/image/bmp/writer.go166
-rw-r--r--tg/pbot/vendor/golang.org/x/image/draw/draw.go43
-rw-r--r--tg/pbot/vendor/golang.org/x/image/draw/gen.go1403
-rw-r--r--tg/pbot/vendor/golang.org/x/image/draw/go1_8.go49
-rw-r--r--tg/pbot/vendor/golang.org/x/image/draw/go1_9.go57
-rw-r--r--tg/pbot/vendor/golang.org/x/image/draw/impl.go6668
-rw-r--r--tg/pbot/vendor/golang.org/x/image/draw/scale.go527
-rw-r--r--tg/pbot/vendor/golang.org/x/image/draw/stdlib_test.go96
-rw-r--r--tg/pbot/vendor/golang.org/x/image/font/basicfont/basicfont.go126
-rw-r--r--tg/pbot/vendor/golang.org/x/image/font/basicfont/data.go1456
-rw-r--r--tg/pbot/vendor/golang.org/x/image/font/basicfont/gen.go115
-rw-r--r--tg/pbot/vendor/golang.org/x/image/font/font.go359
-rw-r--r--tg/pbot/vendor/golang.org/x/image/math/f64/f64.go37
-rw-r--r--tg/pbot/vendor/golang.org/x/image/math/fixed/fixed.go410
-rw-r--r--tg/pbot/vendor/golang.org/x/image/riff/riff.go193
-rw-r--r--tg/pbot/vendor/golang.org/x/image/tiff/buffer.go69
-rw-r--r--tg/pbot/vendor/golang.org/x/image/tiff/compress.go58
-rw-r--r--tg/pbot/vendor/golang.org/x/image/tiff/consts.go133
-rw-r--r--tg/pbot/vendor/golang.org/x/image/tiff/lzw/reader.go272
-rw-r--r--tg/pbot/vendor/golang.org/x/image/tiff/reader.go681
-rw-r--r--tg/pbot/vendor/golang.org/x/image/tiff/writer.go438
-rw-r--r--tg/pbot/vendor/golang.org/x/image/vp8/decode.go403
-rw-r--r--tg/pbot/vendor/golang.org/x/image/vp8/filter.go273
-rw-r--r--tg/pbot/vendor/golang.org/x/image/vp8/idct.go98
-rw-r--r--tg/pbot/vendor/golang.org/x/image/vp8/partition.go129
-rw-r--r--tg/pbot/vendor/golang.org/x/image/vp8/pred.go201
-rw-r--r--tg/pbot/vendor/golang.org/x/image/vp8/predfunc.go553
-rw-r--r--tg/pbot/vendor/golang.org/x/image/vp8/quant.go98
-rw-r--r--tg/pbot/vendor/golang.org/x/image/vp8/reconstruct.go442
-rw-r--r--tg/pbot/vendor/golang.org/x/image/vp8/token.go381
-rw-r--r--tg/pbot/vendor/golang.org/x/image/vp8l/decode.go603
-rw-r--r--tg/pbot/vendor/golang.org/x/image/vp8l/huffman.go245
-rw-r--r--tg/pbot/vendor/golang.org/x/image/vp8l/transform.go299
-rw-r--r--tg/pbot/vendor/golang.org/x/image/webp/decode.go272
-rw-r--r--tg/pbot/vendor/golang.org/x/image/webp/webp.go30
-rw-r--r--tg/pbot/vendor/gopkg.in/telegram-bot-api.v4/bot.go695
-rw-r--r--tg/pbot/vendor/gopkg.in/telegram-bot-api.v4/configs.go789
-rw-r--r--tg/pbot/vendor/gopkg.in/telegram-bot-api.v4/helpers.go611
-rw-r--r--tg/pbot/vendor/gopkg.in/telegram-bot-api.v4/types.go627
91 files changed, 30340 insertions, 0 deletions
diff --git a/tg/pbot/main.go b/tg/pbot/main.go
new file mode 100644
index 0000000..00a342d
--- /dev/null
+++ b/tg/pbot/main.go
@@ -0,0 +1,139 @@
+package main
+
+import (
+ "fmt"
+ "image"
+ "log"
+ "net/http"
+ "os"
+ "runtime"
+ "time"
+
+ "github.com/Xe/uuid"
+ "github.com/fogleman/primitive/primitive"
+ _ "github.com/joho/godotenv/autoload"
+ "gopkg.in/telegram-bot-api.v4"
+
+ // image formats
+ _ "image/jpeg"
+ _ "image/png"
+
+ _ "github.com/hullerob/go.farbfeld"
+ _ "golang.org/x/image/bmp"
+ _ "golang.org/x/image/tiff"
+ _ "golang.org/x/image/webp"
+)
+
+func main() {
+ bot, err := tgbotapi.NewBotAPI(os.Getenv("TELEGRAM_TOKEN"))
+ if err != nil {
+ log.Panic(err)
+ }
+
+ ps, ok := puushLogin(os.Getenv("PUUSH_KEY"))
+ if !ok {
+ log.Fatal("puush login failed")
+ }
+
+ u := tgbotapi.NewUpdate(0)
+ u.Timeout = 60
+
+ updates, err := bot.GetUpdatesChan(u)
+
+ for update := range updates {
+ if update.Message == nil {
+ continue
+ }
+
+ err := renderImg(bot, ps, update)
+ if err != nil {
+ msg := tgbotapi.NewMessage(update.Message.Chat.ID, "error: "+err.Error())
+ log.Printf("error in processing message from %s: %v", update.Message.From.String(), err)
+ bot.Send(msg)
+ }
+ }
+}
+
+func stepImg(img image.Image, count int) image.Image {
+ bg := primitive.MakeColor(primitive.AverageImageColor(img))
+ model := primitive.NewModel(img, bg, 512, runtime.NumCPU())
+
+ for range make([]struct{}, count) {
+ model.Step(primitive.ShapeTypeTriangle, 128, 0)
+ }
+
+ return model.Context.Image()
+}
+
+func renderImg(bot *tgbotapi.BotAPI, ps string, update tgbotapi.Update) error {
+ msg := update.Message
+
+ // ignore chats without photos
+ if len(*msg.Photo) == 0 {
+ return nil
+ }
+
+ p := *msg.Photo
+ pho := p[len(p)-1]
+ fu, err := bot.GetFileDirectURL(pho.FileID)
+ if err != nil {
+ return err
+ }
+
+ resp, err := http.Get(fu)
+ if err != nil {
+ return err
+ }
+ defer resp.Body.Close()
+
+ img, ifmt, err := image.Decode(resp.Body)
+ if err != nil {
+ return err
+ }
+
+ log.Printf("%s: image id %s loaded (%s)", msg.From, pho.FileID, ifmt)
+ umsg := tgbotapi.NewMessage(update.Message.Chat.ID, "rendering... (may take a while)")
+ bot.Send(umsg)
+
+ before := time.Now()
+ imgs := []image.Image{}
+
+ for i := range make([]struct{}, 10) {
+ log.Printf("%s: starting frame render", msg.From)
+ imgs = append(imgs, stepImg(img, 150))
+ log.Printf("%s: frame rendered", msg.From)
+
+ umsg = tgbotapi.NewMessage(update.Message.Chat.ID, fmt.Sprintf("frame %d/10 rendered", i+1))
+ bot.Send(umsg)
+ }
+
+ gpath := "./var/" + update.Message.From.String() + ".gif"
+ err = primitive.SaveGIFImageMagick(gpath, imgs, 15, 15)
+ if err != nil {
+ return err
+ }
+
+ after := time.Now().Sub(before)
+
+ buf, err := os.Open(gpath)
+ if err != nil {
+ return err
+ }
+ defer os.Remove(gpath)
+
+ umsg = tgbotapi.NewMessage(update.Message.Chat.ID, "uploading (took "+after.String()+" to render)")
+ bot.Send(umsg)
+
+ furl, err := puush(ps, uuid.New()+".gif", buf)
+ if err != nil {
+ return err
+ }
+
+ omsg := tgbotapi.NewMessage(update.Message.Chat.ID, furl.String())
+ _, err = bot.Send(omsg)
+ if err != nil {
+ return err
+ }
+
+ return nil
+}
diff --git a/tg/pbot/puush.go b/tg/pbot/puush.go
new file mode 100644
index 0000000..259cb56
--- /dev/null
+++ b/tg/pbot/puush.go
@@ -0,0 +1,93 @@
+package main
+
+import (
+ "bytes"
+ "crypto/md5"
+ "errors"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "mime/multipart"
+ "net/http"
+ "net/url"
+ "strings"
+)
+
+// Puush constants
+const (
+ PuushBase = "https://puush.me/api/"
+ PuushAuthURL = "https://puush.me/api/auth/"
+ PuushUploadURL = "https://puush.me/api/up/"
+)
+
+func puushLogin(key string) (string, bool) {
+ r, err := http.PostForm(PuushAuthURL, url.Values{"k": {key}})
+ if err != nil {
+ fmt.Println(err)
+ return "", false
+ }
+ body, _ := ioutil.ReadAll(r.Body)
+ r.Body.Close()
+ info := strings.Split(string(body), ",")
+ if info[0] == "-1" {
+ return "", false
+ }
+
+ session := info[1]
+ return session, true
+}
+
+func puush(session, fname string, fin io.Reader) (*url.URL, error) {
+ buf := new(bytes.Buffer)
+ w := multipart.NewWriter(buf)
+ kwriter, err := w.CreateFormField("k")
+ if err != nil {
+ return nil, err
+ }
+
+ io.WriteString(kwriter, session)
+
+ file, _ := ioutil.ReadAll(fin)
+
+ h := md5.New()
+ h.Write(file)
+
+ cwriter, err := w.CreateFormField("c")
+ if err != nil {
+ return nil, err
+ }
+ io.WriteString(cwriter, fmt.Sprintf("%x", h.Sum(nil)))
+
+ zwriter, err := w.CreateFormField("z")
+ if err != nil {
+ return nil, err
+ }
+ io.WriteString(zwriter, "poop") // They must think their protocol is shit
+
+ fwriter, err := w.CreateFormFile("f", fname)
+ if err != nil {
+ return nil, err
+ }
+ fwriter.Write(file)
+
+ w.Close()
+
+ req, err := http.NewRequest("POST", "http://puush.me/api/up", buf)
+ if err != nil {
+ return nil, err
+ }
+ req.Header.Set("Content-Type", w.FormDataContentType())
+ client := &http.Client{}
+ res, err := client.Do(req)
+ if err != nil {
+ return nil, err
+ }
+ body, _ := ioutil.ReadAll(res.Body)
+ res.Body.Close()
+ info := strings.Split(string(body), ",")
+ if info[0] == "0" {
+ return url.Parse(info[1])
+ }
+
+ return nil, errors.New("upload failed")
+}
diff --git a/tg/pbot/vendor-log b/tg/pbot/vendor-log
new file mode 100644
index 0000000..1fe2451
--- /dev/null
+++ b/tg/pbot/vendor-log
@@ -0,0 +1,22 @@
+62b230097e9c9534ca2074782b25d738c4b68964 (dirty) github.com/Xe/uuid
+ee8994ff90057955c428a5a949da5d064bf3ce6b github.com/fogleman/gg
+80f39ceaa8f4c66acb28aba6abe6b15128c06113 github.com/fogleman/primitive/primitive
+bcfeb16b74e8aea9e2fe043406f2ef74b1cb0759 github.com/golang/freetype/raster
+bcfeb16b74e8aea9e2fe043406f2ef74b1cb0759 github.com/golang/freetype/truetype
+b572f0728b691aae4256edb2e408279146eafe52 github.com/hullerob/go.farbfeld
+325433c502d409f3c3dc820098fb0cfe38d98dc7 github.com/joho/godotenv
+325433c502d409f3c3dc820098fb0cfe38d98dc7 github.com/joho/godotenv/autoload
+a90a01d73ae432e2611d178c18367fbaa13e0154 github.com/technoweenie/multipartstreamer
+426cfd8eeb6e08ab1932954e09e3c2cb2bc6e36d golang.org/x/image/bmp
+426cfd8eeb6e08ab1932954e09e3c2cb2bc6e36d golang.org/x/image/draw
+426cfd8eeb6e08ab1932954e09e3c2cb2bc6e36d golang.org/x/image/font
+426cfd8eeb6e08ab1932954e09e3c2cb2bc6e36d golang.org/x/image/font/basicfont
+426cfd8eeb6e08ab1932954e09e3c2cb2bc6e36d golang.org/x/image/math/f64
+426cfd8eeb6e08ab1932954e09e3c2cb2bc6e36d golang.org/x/image/math/fixed
+426cfd8eeb6e08ab1932954e09e3c2cb2bc6e36d golang.org/x/image/riff
+426cfd8eeb6e08ab1932954e09e3c2cb2bc6e36d golang.org/x/image/tiff
+426cfd8eeb6e08ab1932954e09e3c2cb2bc6e36d golang.org/x/image/tiff/lzw
+426cfd8eeb6e08ab1932954e09e3c2cb2bc6e36d golang.org/x/image/vp8
+426cfd8eeb6e08ab1932954e09e3c2cb2bc6e36d golang.org/x/image/vp8l
+426cfd8eeb6e08ab1932954e09e3c2cb2bc6e36d golang.org/x/image/webp
+0a57807db79efce7f6719fbb2c0e0f83fda79aec (dirty) gopkg.in/telegram-bot-api.v4
diff --git a/tg/pbot/vendor/github.com/Xe/uuid/dce.go b/tg/pbot/vendor/github.com/Xe/uuid/dce.go
new file mode 100644
index 0000000..50a0f2d
--- /dev/null
+++ b/tg/pbot/vendor/github.com/Xe/uuid/dce.go
@@ -0,0 +1,84 @@
+// Copyright 2011 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package uuid
+
+import (
+ "encoding/binary"
+ "fmt"
+ "os"
+)
+
+// A Domain represents a Version 2 domain
+type Domain byte
+
+// Domain constants for DCE Security (Version 2) UUIDs.
+const (
+ Person = Domain(0)
+ Group = Domain(1)
+ Org = Domain(2)
+)
+
+// NewDCESecurity returns a DCE Security (Version 2) UUID.
+//
+// The domain should be one of Person, Group or Org.
+// On a POSIX system the id should be the users UID for the Person
+// domain and the users GID for the Group. The meaning of id for
+// the domain Org or on non-POSIX systems is site defined.
+//
+// For a given domain/id pair the same token may be returned for up to
+// 7 minutes and 10 seconds.
+func NewDCESecurity(domain Domain, id uint32) UUID {
+ uuid := NewUUID()
+ if uuid != nil {
+ uuid[6] = (uuid[6] & 0x0f) | 0x20 // Version 2
+ uuid[9] = byte(domain)
+ binary.BigEndian.PutUint32(uuid[0:], id)
+ }
+ return uuid
+}
+
+// NewDCEPerson returns a DCE Security (Version 2) UUID in the person
+// domain with the id returned by os.Getuid.
+//
+// NewDCEPerson(Person, uint32(os.Getuid()))
+func NewDCEPerson() UUID {
+ return NewDCESecurity(Person, uint32(os.Getuid()))
+}
+
+// NewDCEGroup returns a DCE Security (Version 2) UUID in the group
+// domain with the id returned by os.Getgid.
+//
+// NewDCEGroup(Group, uint32(os.Getgid()))
+func NewDCEGroup() UUID {
+ return NewDCESecurity(Group, uint32(os.Getgid()))
+}
+
+// Domain returns the domain for a Version 2 UUID or false.
+func (uuid UUID) Domain() (Domain, bool) {
+ if v, _ := uuid.Version(); v != 2 {
+ return 0, false
+ }
+ return Domain(uuid[9]), true
+}
+
+// Id returns the id for a Version 2 UUID or false.
+func (uuid UUID) Id() (uint32, bool) {
+ if v, _ := uuid.Version(); v != 2 {
+ return 0, false
+ }
+ return binary.BigEndian.Uint32(uuid[0:4]), true
+}
+
+func (d Domain) String() string {
+ switch d {
+ case Person:
+ return "Person"
+ case Group:
+ return "Group"
+ case Org:
+ return "Org"
+ }
+ return fmt.Sprintf("Domain%d", int(d))
+}
diff --git a/tg/pbot/vendor/github.com/Xe/uuid/doc.go b/tg/pbot/vendor/github.com/Xe/uuid/doc.go
new file mode 100644
index 0000000..d8bd013
--- /dev/null
+++ b/tg/pbot/vendor/github.com/Xe/uuid/doc.go