gosora/common/thumbnailer.go
Azareal 01a692ab5b Added the word filter store and moved the word filter routes into the route package.
Added tests for the word filter store.
Added qgen.NewAcc() to reduce the amount of boilerplate needed for creating an accumulator.
Exposed the RecordError method on the accumulator.
Added an Add method to PluginList and removed AddPlugin() in favour of that.

More panel buttons on Nox should be styled now.
Added the panel_update_button_text phrase for future use.

More errors might be caught in the thumbnailer now.
Removed ls from .travis.yml, it was there for debugging Code Climate.
2018-08-04 21:46:36 +10:00

146 lines
3.7 KiB
Go

package common
import (
"image"
"image/gif"
"image/jpeg"
_ "image/png"
"os"
"strconv"
"../query_gen/lib"
"github.com/pkg/errors"
)
func ThumbTask(thumbChan chan bool) {
for {
// Put this goroutine to sleep until we have work to do
<-thumbChan
// TODO: Use a real queue
acc := qgen.NewAcc()
err := acc.Select("users_avatar_queue").Columns("uid").Limit("0,5").EachInt(func(uid int) error {
// TODO: Do a bulk user fetch instead?
user, err := Users.Get(uid)
if err != nil {
return errors.WithStack(err)
}
// Has the avatar been removed or already been processed by the thumbnailer?
if len(user.RawAvatar) < 2 || user.RawAvatar[1] == '.' {
_, _ = acc.Delete("users_avatar_queue").Where("uid = ?").Run(uid)
return nil
}
// This means it's an external image, they aren't currently implemented, but this is here for when they are
if user.RawAvatar[0] != '.' {
return nil
}
/*if user.RawAvatar == ".gif" {
return nil
}*/
if user.RawAvatar != ".png" && user.RawAvatar != ".jpg" && user.RawAvatar != ".jpeg" && user.RawAvatar != ".gif" {
return nil
}
err = Thumbnailer.Resize(user.RawAvatar[1:], "./uploads/avatar_"+strconv.Itoa(user.ID)+user.RawAvatar, "./uploads/avatar_"+strconv.Itoa(user.ID)+"_tmp"+user.RawAvatar, "./uploads/avatar_"+strconv.Itoa(user.ID)+"_w48"+user.RawAvatar, 48)
if err != nil {
return errors.WithStack(err)
}
err = user.ChangeAvatar("." + user.RawAvatar)
if err != nil {
return errors.WithStack(err)
}
_, err = acc.Delete("users_avatar_queue").Where("uid = ?").Run(uid)
return errors.WithStack(err)
})
if err != nil {
LogError(err)
}
if err = acc.FirstError(); err != nil {
LogError(err)
}
}
}
var Thumbnailer ThumbnailerInt
type ThumbnailerInt interface {
Resize(format string, inPath string, tmpPath string, outPath string, width int) error
}
type RezThumbnailer struct {
}
func (thumb *RezThumbnailer) Resize(format string, inPath string, tmpPath string, outPath string, width int) error {
// TODO: Sniff the aspect ratio of the image and calculate the dest height accordingly, bug make sure it isn't excessively high
return nil
}
func (thumb *RezThumbnailer) resize(format string, inPath string, outPath string, width int, height int) error {
return nil
}
// ! Note: CaireThumbnailer can't handle gifs, so we'll have to either cap their sizes or have another resizer deal with them
type CaireThumbnailer struct {
}
func NewCaireThumbnailer() *CaireThumbnailer {
return &CaireThumbnailer{}
}
func precodeImage(format string, inPath string, tmpPath string) error {
imageFile, err := os.Open(inPath)
if err != nil {
return err
}
defer imageFile.Close()
img, _, err := image.Decode(imageFile)
if err != nil {
return err
}
outFile, err := os.Create(tmpPath)
if err != nil {
return err
}
defer outFile.Close()
// TODO: Make sure animated gifs work after being encoded
if format == "gif" {
return gif.Encode(outFile, img, nil)
}
return jpeg.Encode(outFile, img, nil)
}
func (thumb *CaireThumbnailer) Resize(format string, inPath string, tmpPath string, outPath string, width int) error {
err := precodeImage(format, inPath, tmpPath)
if err != nil {
return err
}
return nil
// TODO: Caire doesn't work. Try something else. Or get them to fix the index out of range. We get enough wins from re-encoding as jpeg anyway
/*imageFile, err := os.Open(tmpPath)
if err != nil {
return err
}
defer imageFile.Close()
outFile, err := os.Create(outPath)
if err != nil {
return err
}
defer outFile.Close()
p := &caire.Processor{NewWidth: width, Scale: true}
return p.Process(imageFile, outFile)*/
}
/*
type LilliputThumbnailer struct {
}
*/