This repository has been archived on 2023-07-05. You can view files and clone it, but cannot push or open issues or pull requests.
clessy/mods/snapchat.go

223 lines
5.6 KiB
Go

package main
import (
"bytes"
"encoding/base64"
"image"
"image/color"
_ "image/gif"
"image/jpeg"
_ "image/png"
"io/ioutil"
"log"
"math/rand"
"os"
"strings"
"unicode"
"time"
"git.fromouter.space/crunchy-rocks/draw2d"
"git.fromouter.space/crunchy-rocks/draw2d/draw2dimg"
"git.fromouter.space/crunchy-rocks/freetype"
"git.fromouter.space/hamcha/tg"
)
var snapFontData draw2d.FontData
func snapchat_init() {
rand.Seed(time.Now().Unix())
fontfile, err := os.Open(*sourcesans)
assert(err)
defer fontfile.Close()
bytes, err := ioutil.ReadAll(fontfile)
assert(err)
font, err := freetype.ParseFont(bytes)
assert(err)
snapFontData = draw2d.FontData{"sourcesans", draw2d.FontFamilySans, draw2d.FontStyleBold}
draw2d.RegisterFont(snapFontData, font)
log.Println("[snapchat] Loaded!")
}
func snapchat_message(broker *tg.Broker, update tg.APIMessage) {
// Make replies work
if update.ReplyTo != nil && update.Text != nil && update.ReplyTo.Photo != nil {
update.Photo = update.ReplyTo.Photo
update.Caption = update.Text
}
if update.Photo != nil && update.Caption != nil {
caption := *(update.Caption)
if strings.HasPrefix(caption, "/snap ") && len(caption) > 6 {
txt := strings.TrimSpace(caption[6:])
maxsz := 0
photo := tg.APIPhotoSize{}
for _, curphoto := range update.Photo {
if curphoto.Width > maxsz {
maxsz = curphoto.Width
photo = curphoto
}
}
broker.GetFile(photo.FileID, func(broker *tg.Broker, data tg.BrokerUpdate) {
if data.Type == tg.BError {
log.Printf("[snapchat] Received error from broker: %s\n", *data.Error)
broker.SendTextMessage(update.Chat, "<b>ERRORE!</b> @hamcha controlla la console!", &update.MessageID)
return
}
pbytes, err := base64.StdEncoding.DecodeString(*data.Bytes)
if err != nil {
log.Printf("[snapchat] Base64 decode error: %s\n", err.Error())
broker.SendTextMessage(update.Chat, "<b>ERRORE!</b> @hamcha controlla la console!", &update.MessageID)
return
}
img, _, err := image.Decode(bytes.NewReader(pbytes))
if err != nil {
log.Printf("[snapchat] Image decode error: %s\n", err.Error())
broker.SendTextMessage(update.Chat, "<b>ERROR</b>: Non riesco a leggere l'immagine", &update.MessageID)
return
}
broker.SendChatAction(update.Chat, tg.ActionUploadingPhoto)
// Create target image
bounds := img.Bounds()
iwidth := float64(bounds.Size().Y) / 1.6
iheight := float64(bounds.Size().Y)
repos := iwidth < float64(bounds.Size().X)
if !repos {
iwidth = float64(bounds.Size().X)
}
timg := image.NewRGBA(image.Rect(0, 0, int(iwidth), int(iheight)))
gc := draw2dimg.NewGraphicContext(timg)
gc.Emojis = emojis
gc.SetFontData(snapFontData)
gc.Save()
if repos {
gc.Translate(-(float64(bounds.Size().X)-iwidth)/2, 0)
}
gc.DrawImage(img)
gc.Restore()
scale := iwidth / 25
gc.SetFontSize(scale)
lineMargin := scale / 3
boxMargin := lineMargin
topMargin := lineMargin / 6
write := func(text string, startHeight float64) {
texts := wordWrap(gc, strings.TrimSpace(text), iwidth*0.9)
totalHeight := startHeight
firstLine := 0.
for _, txt := range texts {
_, top, _, bottom := gc.GetStringBounds(txt)
height := (bottom - top)
if firstLine == 0 {
firstLine = height
}
totalHeight += lineMargin + height
}
// Draw background
starty := startHeight - boxMargin - topMargin - firstLine
endy := totalHeight + boxMargin - firstLine
gc.Save()
gc.SetFillColor(color.RGBA{0, 0, 0, 160})
gc.BeginPath()
gc.MoveTo(0, starty)
gc.LineTo(iwidth, starty)
gc.LineTo(iwidth, endy)
gc.LineTo(0, endy)
gc.Close()
gc.Fill()
gc.Restore()
// Write lines
gc.SetFillColor(image.White)
height := startHeight
for _, txt := range texts {
left, top, right, bottom := gc.GetStringBounds(txt)
width := right - left
gc.FillStringAt(txt, (iwidth-width)/2, height)
height += lineMargin + (bottom - top)
}
}
write(txt, (rand.Float64()*0.4+0.3)*iheight)
buf := new(bytes.Buffer)
err = jpeg.Encode(buf, timg, &(jpeg.Options{Quality: 80}))
if err != nil {
log.Printf("[snapchat] Image encode error: %s\n", err.Error())
broker.SendTextMessage(update.Chat, "<b>ERRORE!</b> @hamcha controlla la console!", &update.MessageID)
return
}
broker.SendPhoto(update.Chat, buf.Bytes(), "meme.jpg", "", &update.MessageID)
})
}
}
}
// Word wrapping code from https://github.com/fogleman/gg
// Copyright (C) 2016 Michael Fogleman
// Licensed under MIT (https://github.com/fogleman/gg/blob/master/LICENSE.md)
func splitOnSpace(x string) []string {
var result []string
pi := 0
ps := false
for i, c := range x {
s := unicode.IsSpace(c)
if s != ps && i > 0 {
result = append(result, x[pi:i])
pi = i
}
ps = s
}
result = append(result, x[pi:])
return result
}
func wordWrap(gc draw2d.GraphicContext, s string, width float64) []string {
var result []string
for _, line := range strings.Split(s, "\n") {
fields := splitOnSpace(line)
if len(fields)%2 == 1 {
fields = append(fields, "")
}
x := ""
for i := 0; i < len(fields); i += 2 {
left, _, right, _ := gc.GetStringBounds(x + fields[i])
w := right - left
if w > width {
if x == "" {
result = append(result, fields[i])
x = ""
continue
} else {
result = append(result, x)
x = ""
}
}
x += fields[i] + fields[i+1]
}
if x != "" {
result = append(result, x)
}
}
for i, line := range result {
result[i] = strings.TrimSpace(line)
}
return result
}