From 4fd96b866bdbd8d9d44b1b1b75739cd432d248cd Mon Sep 17 00:00:00 2001 From: Karar Al-Remahy Date: Sun, 24 Apr 2022 00:00:13 +0200 Subject: [PATCH 01/14] init --- go.mod | 12 +++-- go.sum | 11 ++-- pkg/thumbnail/thumbnail_unix.go | 90 +++++++++++++++------------------ 3 files changed, 56 insertions(+), 57 deletions(-) diff --git a/go.mod b/go.mod index 737dc688..0d10bab0 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,6 @@ go 1.17 require ( github.com/PuerkitoBio/goquery v1.8.0 - github.com/discord/lilliput v0.0.0-20210720001558-e1547514bd5f github.com/dyatlov/go-oembed v0.0.0-20191103150536-a57c85b3b37c github.com/frankban/quicktest v1.14.3 github.com/go-chi/chi/v5 v5.0.7 @@ -51,7 +50,6 @@ require ( github.com/kr/pretty v0.3.0 // indirect github.com/kr/text v0.2.0 // indirect github.com/magiconair/properties v1.8.6 // indirect - github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect github.com/mitchellh/mapstructure v1.4.3 // indirect github.com/pelletier/go-toml v1.9.4 // indirect github.com/pelletier/go-toml/v2 v2.0.0-beta.8 // indirect @@ -68,8 +66,8 @@ require ( go.uber.org/multierr v1.6.0 // indirect golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 // indirect golang.org/x/exp/typeparams v0.0.0-20220218215828-6cf2b201936e // indirect + golang.org/x/image v0.0.0-20200927104501-e162460cd6b5 // indirect golang.org/x/mod v0.5.1 // indirect - golang.org/x/net v0.0.0-20220412020605-290c469a71a5 // indirect golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5 // indirect golang.org/x/sys v0.0.0-20220412211240-33da011f77ad // indirect golang.org/x/text v0.3.7 // indirect @@ -79,8 +77,14 @@ require ( google.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4 // indirect google.golang.org/grpc v1.45.0 // indirect google.golang.org/protobuf v1.28.0 // indirect - gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/ini.v1 v1.66.4 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect ) + +require ( + github.com/davidbyttow/govips/v2 v2.11.0 + github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect + golang.org/x/net v0.0.0-20220421235706-1d1ef9303861 // indirect + gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect +) diff --git a/go.sum b/go.sum index 39472657..befa0b2e 100644 --- a/go.sum +++ b/go.sum @@ -117,8 +117,8 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3 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/discord/lilliput v0.0.0-20210720001558-e1547514bd5f h1:vM63WJhNbdzbgQdZv+6aNy8TUvj7y3hxuYdIWB6SGro= -github.com/discord/lilliput v0.0.0-20210720001558-e1547514bd5f/go.mod h1:0euuUBAD72MAYRm2ElLaG1h0nBR+CgpfnKc/U6y/uE8= +github.com/davidbyttow/govips/v2 v2.11.0 h1:eJY+Sgt2LRVh6TFSNMnl5rrFkDfuToG5uE5aLSV1jvM= +github.com/davidbyttow/govips/v2 v2.11.0/go.mod h1:goq38QD8XEMz2aWEeucEZqRxAWsemIN40vbUqfPfTAw= github.com/dyatlov/go-oembed v0.0.0-20191103150536-a57c85b3b37c h1:MEV1LrQtCBGacXajlT4CSuYWbZuLl/qaZVqwoOmwAbU= github.com/dyatlov/go-oembed v0.0.0-20191103150536-a57c85b3b37c/go.mod h1:DjlDZiZGRRKbiJZmiEiiXozsBQAQzHmxwHKFeXifL2g= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= @@ -406,6 +406,7 @@ github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6 github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8= github.com/nicklaw5/helix v1.25.0 h1:Mrz537izZVsGdM3I46uGAAlslj61frgkhS/9xQqyT/M= github.com/nicklaw5/helix v1.25.0/go.mod h1:yvXZFapT6afIoxnAvlWiJiUMsYnoHl7tNs+t0bloAMw= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pashagolub/pgxmock v1.4.4 h1:g9d6q9YK95I0QQYq6x0j2sibVct5rpJKSdO2IQVg3gc= @@ -565,6 +566,8 @@ golang.org/x/exp/typeparams v0.0.0-20220218215828-6cf2b201936e h1:qyrTQ++p1afMkO golang.org/x/exp/typeparams v0.0.0-20220218215828-6cf2b201936e/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20200927104501-e162460cd6b5 h1:QelT11PB4FXiDEXucrfNckHoFxwt8USGY1ajP1ZF5lM= +golang.org/x/image v0.0.0-20200927104501-e162460cd6b5/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -638,8 +641,9 @@ golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220412020605-290c469a71a5 h1:bRb386wvrE+oBNdF1d/Xh9mQrfQ4ecYhW5qJ5GvTGT4= golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220421235706-1d1ef9303861 h1:yssD99+7tqHWO5Gwh81phT+67hg+KttniBr6UnEXOY8= +golang.org/x/net v0.0.0-20220421235706-1d1ef9303861/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1009,6 +1013,7 @@ gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLks gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= diff --git a/pkg/thumbnail/thumbnail_unix.go b/pkg/thumbnail/thumbnail_unix.go index b41fca30..347b8846 100644 --- a/pkg/thumbnail/thumbnail_unix.go +++ b/pkg/thumbnail/thumbnail_unix.go @@ -6,58 +6,43 @@ package thumbnail import ( "fmt" "net/http" - "strings" - "github.com/discord/lilliput" -) - -var ( - encodeOptions = map[string]map[int]int{ - ".jpeg": {lilliput.JpegQuality: 85}, - ".png": {lilliput.PngCompression: 7}, - ".webp": {lilliput.WebpQuality: 85}, - } + "github.com/davidbyttow/govips/v2/vips" ) func BuildAnimatedThumbnail(inputBuf []byte, resp *http.Response) ([]byte, error) { - // decoder wants []byte, so read the whole file into a buffer - decoder, err := lilliput.NewDecoder(inputBuf) - // this error reflects very basic checks, - // mostly just for the magic bytes of the file to match known image formats - if err != nil { - return []byte{}, fmt.Errorf("could not decode image from url: %s", resp.Request.URL) - } - defer decoder.Close() + // Only resize if the original image has bigger dimensions than maxThumbnailSize + // if newWidth < maxThumbnailSize && newHeight < maxThumbnailSize { + // // We don't need to resize image nor does it need to be passed through govips. + // return inputBuf, nil + // } - header, err := decoder.Header() - // this error is much more comprehensive and reflects - // format errors - if err != nil { - return []byte{}, fmt.Errorf("could not read image header from url: %s", resp.Request.URL) - } + // vips.Startup(nil) + // defer vips.Shutdown() - newWidth := header.Width() - newHeight := header.Height() + fmt.Println("yo") - // get ready to resize image, - ops := lilliput.NewImageOps(8192) - defer ops.Close() + image, err := vips.NewImageFromBuffer(inputBuf) - // create a buffer to store the output image, 2MB in this case - // If the final image does not fit within this buffer, then we fall back to providing a static thumbnail - outputImg := make([]byte, 2*1024*1024) + params := vips.NewImportParams() + format := image.Format() - // lilliput has the height & width values in int, which means we're converting uint to int. - maxThumbnailSize := int(cfg.MaxThumbnailSize) + // n=-1 is used for gifs & webps to make sure to get all frames and not just the first one. + if format == vips.ImageTypeGIF || format == vips.ImageTypeWEBP { + params.NumPages.Set(-1) + } - // We don't need to resize image nor does it need to be passed through lilliput. - // Only resize if the original image has bigger dimensions than maxThumbnailSize - if newWidth < maxThumbnailSize && newHeight < maxThumbnailSize { - return inputBuf, nil + if err != nil { + return []byte{}, fmt.Errorf("could not load image from url: %s", resp.Request.URL) } - // don't transcode (use existing type) - outputType := "." + strings.ToLower(decoder.Description()) + // govips has the height & width values in int, which means we're converting uint to int. + maxThumbnailSize := int(cfg.MaxThumbnailSize) + + newWidth := image.Width() + newHeight := image.Height() + + fmt.Println(newWidth, "x", newHeight) /* Preserve aspect ratio is from previous module, thanks nfnt/resize. * (https://github.com/nfnt/resize/blob/83c6a9932646f83e3267f353373d47347b6036b2/thumbnail.go#L27) @@ -80,19 +65,24 @@ func BuildAnimatedThumbnail(inputBuf []byte, resp *http.Response) ([]byte, error newHeight = maxThumbnailSize } - opts := &lilliput.ImageOptions{ - FileType: outputType, - Width: newWidth, - Height: newHeight, - ResizeMethod: lilliput.ImageOpsResize, - EncodeOptions: encodeOptions[outputType], - } + fmt.Println(newWidth, "x", newHeight) + + image, err = vips.LoadThumbnailFromBuffer(inputBuf, newWidth, newHeight, vips.InterestingAll, vips.SizeBoth, params) - // resize and transcode image - outputImg, err = ops.Transform(decoder, opts, outputImg) if err != nil { + fmt.Println(err) return []byte{}, fmt.Errorf("could not transform image from url: %s", resp.Request.URL) } - return outputImg, nil + exportParams := vips.NewWebpExportParams() + exportParams.Quality = 10 + + outputBuf, _, err := image.ExportWebp(exportParams) + + fmt.Println("size before:", len(inputBuf), "size after:", len(outputBuf)) + if err != nil { + return []byte{}, fmt.Errorf("could not export image from url: %s", resp.Request.URL) + } + + return outputBuf, nil } From 7739560613cc2af4d750bf1bc3e8911bd5c9fe9c Mon Sep 17 00:00:00 2001 From: Karar Al-Remahy Date: Mon, 10 Oct 2022 15:47:07 +0200 Subject: [PATCH 02/14] chore: run go mod tidy --- go.mod | 8 -------- go.sum | 2 -- 2 files changed, 10 deletions(-) diff --git a/go.mod b/go.mod index 660275b8..770c012a 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,6 @@ go 1.18 require ( github.com/PuerkitoBio/goquery v1.8.0 github.com/davidbyttow/govips/v2 v2.11.0 - github.com/discord/lilliput v0.0.0-20210720001558-e1547514bd5f github.com/dyatlov/go-oembed v0.0.0-20191103150536-a57c85b3b37c github.com/frankban/quicktest v1.14.3 github.com/go-chi/chi/v5 v5.0.7 @@ -86,10 +85,3 @@ require ( gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) - -require ( - github.com/davidbyttow/govips/v2 v2.11.0 - github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect - golang.org/x/net v0.0.0-20220421235706-1d1ef9303861 // indirect - gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect -) diff --git a/go.sum b/go.sum index a8ce68e4..04c91ba6 100644 --- a/go.sum +++ b/go.sum @@ -110,8 +110,6 @@ 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/davidbyttow/govips/v2 v2.11.0 h1:eJY+Sgt2LRVh6TFSNMnl5rrFkDfuToG5uE5aLSV1jvM= github.com/davidbyttow/govips/v2 v2.11.0/go.mod h1:goq38QD8XEMz2aWEeucEZqRxAWsemIN40vbUqfPfTAw= -github.com/discord/lilliput v0.0.0-20210720001558-e1547514bd5f h1:vM63WJhNbdzbgQdZv+6aNy8TUvj7y3hxuYdIWB6SGro= -github.com/discord/lilliput v0.0.0-20210720001558-e1547514bd5f/go.mod h1:0euuUBAD72MAYRm2ElLaG1h0nBR+CgpfnKc/U6y/uE8= github.com/dyatlov/go-oembed v0.0.0-20191103150536-a57c85b3b37c h1:MEV1LrQtCBGacXajlT4CSuYWbZuLl/qaZVqwoOmwAbU= github.com/dyatlov/go-oembed v0.0.0-20191103150536-a57c85b3b37c/go.mod h1:DjlDZiZGRRKbiJZmiEiiXozsBQAQzHmxwHKFeXifL2g= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= From c0e9a1ef6c64f9b3485a69b1685b0fe9572f0395 Mon Sep 17 00:00:00 2001 From: Karar Al-Remahy Date: Mon, 10 Oct 2022 17:00:27 +0200 Subject: [PATCH 03/14] fix: enableLilliput -> enableAnimatedThumbnails --- config.yaml | 6 +++--- docs/chatterino-api.service | 2 +- internal/resolvers/default/link_resolver.go | 6 +++--- internal/resolvers/default/thumbnail_loader.go | 8 ++++---- pkg/config/config.go | 2 +- pkg/config/model.go | 10 +++++----- 6 files changed, 17 insertions(+), 17 deletions(-) diff --git a/config.yaml b/config.yaml index 8772cae3..34148a16 100644 --- a/config.yaml +++ b/config.yaml @@ -9,9 +9,9 @@ # Max content size in bytes - requests with body bigger than this value will be skipped #max-content-length: 5242880 -# When enabled, will attempt to use lilliput library for building animated thumbnails. -# Can increase memory usage by a lot. -#enable-lilliput: true +# When enabled, will attempt to use libvips library to build animated thumbnails. +# Can increase CPU usage and cache storage by a lot. +#enable-animated-thumbnails: true # Maximum width/height pixel size count of the thumbnails sent to the clients. #max-thumbnail-size: 300 diff --git a/docs/chatterino-api.service b/docs/chatterino-api.service index fdefbe46..6192cf10 100644 --- a/docs/chatterino-api.service +++ b/docs/chatterino-api.service @@ -10,7 +10,7 @@ RestartSec=5s ;Environment="CHATTERINO_API_BASE_URL=" ;Environment="CHATTERINO_API_BIND_ADDRESS=:1234" ;Environment="CHATTERINO_API_MAX_CONTENT_LENGTH=5242880" -;Environment="CHATTERINO_API_ENABLE_LILLIPUT=true" +;Environment="CHATTERINO_API_ENABLE_ANIMATED_THUMBNAILS=true" ;Environment="CHATTERINO_API_DISCORD_TOKEN=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" ;Environment="CHATTERINO_API_CACHE_TWITCH_CLIENT_ID=XXXXXXXXXXXXXXXXXXXXXXXX" ;Environment="CHATTERINO_API_TWITCH_CLIENT_SECRET=XXXXXXXXXXXXXXXXXXXXXXXX" diff --git a/internal/resolvers/default/link_resolver.go b/internal/resolvers/default/link_resolver.go index 7272402a..3ecbb7de 100644 --- a/internal/resolvers/default/link_resolver.go +++ b/internal/resolvers/default/link_resolver.go @@ -190,9 +190,9 @@ func New(ctx context.Context, cfg config.APIConfig, pool db.Pool, helixClient *h customResolvers: customResolvers, } thumbnailLoader := &ThumbnailLoader{ - baseURL: cfg.BaseURL, - maxContentLength: cfg.MaxContentLength, - enableLilliput: cfg.EnableLilliput, + baseURL: cfg.BaseURL, + maxContentLength: cfg.MaxContentLength, + enableAnimatedThumbnails: cfg.EnableAnimatedThumbnails, } r := &LinkResolver{ diff --git a/internal/resolvers/default/thumbnail_loader.go b/internal/resolvers/default/thumbnail_loader.go index f6efae77..1c0a6520 100644 --- a/internal/resolvers/default/thumbnail_loader.go +++ b/internal/resolvers/default/thumbnail_loader.go @@ -19,9 +19,9 @@ import ( ) type ThumbnailLoader struct { - baseURL string - maxContentLength uint64 - enableLilliput bool + baseURL string + maxContentLength uint64 + enableAnimatedThumbnails bool } func (l *ThumbnailLoader) Load(ctx context.Context, urlString string, r *http.Request) ([]byte, *int, *string, time.Duration, error) { @@ -81,7 +81,7 @@ func (l *ThumbnailLoader) Load(ctx context.Context, urlString string, r *http.Re } var image []byte - tryAnimatedThumb := l.enableLilliput && thumbnail.IsAnimatedThumbnailType(contentType) + tryAnimatedThumb := l.enableAnimatedThumbnails && thumbnail.IsAnimatedThumbnailType(contentType) // attempt building an animated image if tryAnimatedThumb { diff --git a/pkg/config/config.go b/pkg/config/config.go index 67bf4e48..80ed0cc8 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -63,7 +63,7 @@ func init() { pflag.StringP("base-url", "b", "", "Base URL to which clients will make their requests. Useful if the API is proxied through reverse proxy like nginx. Value needs to contain full URL with protocol scheme, e.g. https://braize.pajlada.com/chatterino") pflag.StringP("bind-address", "l", ":1234", "Address to which API will bind and start listening on") pflag.Uint64("max-content-length", 5*1024*1024, "Max content size in bytes - requests with body bigger than this value will be skipped") - pflag.Bool("enable-lilliput", true, "When enabled, will attempt to use lilliput library for building animated thumbnails. Can increase memory usage by a lot") + pflag.Bool("enable-animated-thumbnails", true, "When enabled, will attempt to use libvips library to build animated thumbnails. Can increase CPU usage and cache storage by a lot") pflag.Uint("max-thumbnail-size", 300, "Maximum width/height pixel size count of the thumbnails sent to the clients.") pflag.String("log-level", "info", "Log level") pflag.Bool("log-development", false, "Enable development logging for warnings and above, this includes stack traces") diff --git a/pkg/config/model.go b/pkg/config/model.go index 01bfcdc5..b65caa89 100644 --- a/pkg/config/model.go +++ b/pkg/config/model.go @@ -3,11 +3,11 @@ package config type APIConfig struct { // Core - BaseURL string `mapstructure:"base-url" json:"base-url"` - BindAddress string `mapstructure:"bind-address" json:"bind-address"` - MaxContentLength uint64 `mapstructure:"max-content-length" json:"max-content-length"` - EnableLilliput bool `mapstructure:"enable-lilliput" json:"enable-lilliput"` - MaxThumbnailSize uint `mapstructure:"max-thumbnail-size" json:"max-thumbnail-size"` + BaseURL string `mapstructure:"base-url" json:"base-url"` + BindAddress string `mapstructure:"bind-address" json:"bind-address"` + MaxContentLength uint64 `mapstructure:"max-content-length" json:"max-content-length"` + EnableAnimatedThumbnails bool `mapstructure:"enable-animated-thumbnails" json:"enable-animated-thumbnails"` + MaxThumbnailSize uint `mapstructure:"max-thumbnail-size" json:"max-thumbnail-size"` LogLevel string `mapstructure:"log-level" json:"log-level"` LogDevelopment bool `mapstructure:"log-development" json:"log-development"` From ff05d7755d7c577710c57fe555ddc058d24849b2 Mon Sep 17 00:00:00 2001 From: Karar Al-Remahy Date: Mon, 10 Oct 2022 22:39:37 +0200 Subject: [PATCH 04/14] feat: add animated thumbnails to thumbnail.go A lot of duplicate code between the functions, needs a refactor. --- pkg/thumbnail/thumbnail.go | 49 ++++++++++++++++- pkg/thumbnail/thumbnail_unix.go | 88 ------------------------------ pkg/thumbnail/thumbnail_windows.go | 14 ----- 3 files changed, 47 insertions(+), 104 deletions(-) delete mode 100644 pkg/thumbnail/thumbnail_unix.go delete mode 100644 pkg/thumbnail/thumbnail_windows.go diff --git a/pkg/thumbnail/thumbnail.go b/pkg/thumbnail/thumbnail.go index 441c7687..ae804e1e 100644 --- a/pkg/thumbnail/thumbnail.go +++ b/pkg/thumbnail/thumbnail.go @@ -11,7 +11,7 @@ import ( var ( supportedThumbnails = []string{"image/jpeg", "image/png", "image/gif", "image/webp"} - animatedThumbnails = []string{"image/gif", "image/webp"} + animatedThumbnails = []string{"image/gif", "image/webp", "image/avif"} cfg config.APIConfig ) @@ -36,6 +36,10 @@ func Shutdown() { func BuildStaticThumbnail(inputBuf []byte, resp *http.Response) ([]byte, error) { image, err := vips.NewImageFromBuffer(inputBuf) + if err != nil { + return []byte{}, fmt.Errorf("could not load image from url: %s", resp.Request.URL) + } + // govips has the height & width values in int, which means we're converting uint to int. maxThumbnailSize := int(cfg.MaxThumbnailSize) @@ -47,18 +51,59 @@ func BuildStaticThumbnail(inputBuf []byte, resp *http.Response) ([]byte, error) importParams := vips.NewImportParams() + image, err = vips.LoadThumbnailFromBuffer(inputBuf, maxThumbnailSize, maxThumbnailSize, vips.InterestingNone, vips.SizeDown, importParams) + + if err != nil { + fmt.Println(err) + return []byte{}, fmt.Errorf("could not transform image from url: %s", resp.Request.URL) + } + + outputBuf, _, err := image.ExportNative() + + if err != nil { + return []byte{}, fmt.Errorf("could not export image from url: %s", resp.Request.URL) + } + + return outputBuf, nil +} + +func BuildAnimatedThumbnail(inputBuf []byte, resp *http.Response) ([]byte, error) { + image, err := vips.NewImageFromBuffer(inputBuf) + if err != nil { return []byte{}, fmt.Errorf("could not load image from url: %s", resp.Request.URL) } - image, err = vips.LoadThumbnailFromBuffer(inputBuf, maxThumbnailSize, maxThumbnailSize, vips.InterestingNone, vips.SizeDown, importParams) + // govips has the height & width values in int, which means we're converting uint to int. + maxThumbnailSize := int(cfg.MaxThumbnailSize) + + // Only resize if the original image has bigger dimensions than maxThumbnailSize + if image.Width() <= maxThumbnailSize && image.Height() <= maxThumbnailSize { + // We don't need to resize image nor does it need to be passed through govips. + return inputBuf, nil + } + + importParams := vips.NewImportParams() + format := image.Format() + + // n=-1 is used for animated images to make sure to get all frames and not just the first one. + if format == vips.ImageTypeGIF || format == vips.ImageTypeWEBP || format == vips.ImageTypeAVIF { + importParams.NumPages.Set(-1) + } + + image, err = vips.LoadThumbnailFromBuffer(inputBuf, maxThumbnailSize, maxThumbnailSize, vips.InterestingAll, vips.SizeDown, importParams) if err != nil { fmt.Println(err) return []byte{}, fmt.Errorf("could not transform image from url: %s", resp.Request.URL) } + // exportParams := vips.NewWebpExportParams() + // exportParams.Quality = 10 + // outputBuf, _, err := image.ExportWebp(exportParams) + outputBuf, _, err := image.ExportNative() + if err != nil { return []byte{}, fmt.Errorf("could not export image from url: %s", resp.Request.URL) } diff --git a/pkg/thumbnail/thumbnail_unix.go b/pkg/thumbnail/thumbnail_unix.go deleted file mode 100644 index 347b8846..00000000 --- a/pkg/thumbnail/thumbnail_unix.go +++ /dev/null @@ -1,88 +0,0 @@ -//go:build !windows -// +build !windows - -package thumbnail - -import ( - "fmt" - "net/http" - - "github.com/davidbyttow/govips/v2/vips" -) - -func BuildAnimatedThumbnail(inputBuf []byte, resp *http.Response) ([]byte, error) { - // Only resize if the original image has bigger dimensions than maxThumbnailSize - // if newWidth < maxThumbnailSize && newHeight < maxThumbnailSize { - // // We don't need to resize image nor does it need to be passed through govips. - // return inputBuf, nil - // } - - // vips.Startup(nil) - // defer vips.Shutdown() - - fmt.Println("yo") - - image, err := vips.NewImageFromBuffer(inputBuf) - - params := vips.NewImportParams() - format := image.Format() - - // n=-1 is used for gifs & webps to make sure to get all frames and not just the first one. - if format == vips.ImageTypeGIF || format == vips.ImageTypeWEBP { - params.NumPages.Set(-1) - } - - if err != nil { - return []byte{}, fmt.Errorf("could not load image from url: %s", resp.Request.URL) - } - - // govips has the height & width values in int, which means we're converting uint to int. - maxThumbnailSize := int(cfg.MaxThumbnailSize) - - newWidth := image.Width() - newHeight := image.Height() - - fmt.Println(newWidth, "x", newHeight) - - /* Preserve aspect ratio is from previous module, thanks nfnt/resize. - * (https://github.com/nfnt/resize/blob/83c6a9932646f83e3267f353373d47347b6036b2/thumbnail.go#L27) - */ - - // Preserve aspect ratio - if newWidth > maxThumbnailSize { - newHeight = newHeight * maxThumbnailSize / newWidth - if newHeight < 1 { - newHeight = 1 - } - newWidth = maxThumbnailSize - } - - if newHeight > maxThumbnailSize { - newWidth = newWidth * maxThumbnailSize / newHeight - if newWidth < 1 { - newWidth = 1 - } - newHeight = maxThumbnailSize - } - - fmt.Println(newWidth, "x", newHeight) - - image, err = vips.LoadThumbnailFromBuffer(inputBuf, newWidth, newHeight, vips.InterestingAll, vips.SizeBoth, params) - - if err != nil { - fmt.Println(err) - return []byte{}, fmt.Errorf("could not transform image from url: %s", resp.Request.URL) - } - - exportParams := vips.NewWebpExportParams() - exportParams.Quality = 10 - - outputBuf, _, err := image.ExportWebp(exportParams) - - fmt.Println("size before:", len(inputBuf), "size after:", len(outputBuf)) - if err != nil { - return []byte{}, fmt.Errorf("could not export image from url: %s", resp.Request.URL) - } - - return outputBuf, nil -} diff --git a/pkg/thumbnail/thumbnail_windows.go b/pkg/thumbnail/thumbnail_windows.go deleted file mode 100644 index 760f8b02..00000000 --- a/pkg/thumbnail/thumbnail_windows.go +++ /dev/null @@ -1,14 +0,0 @@ -//go:build windows -// +build windows - -package thumbnail - -import ( - "errors" - "net/http" -) - -func BuildAnimatedThumbnail(inputBuf []byte, resp *http.Response) ([]byte, error) { - // Since the lilliput library currently does not support Windows, we error out early and fall back to the static thumbnail generation - return nil, errors.New("cannot build animated thumbnails on windows") -} From 26448c2d8c819c916209adf296818a3c627efcb5 Mon Sep 17 00:00:00 2001 From: Karar Al-Remahy Date: Mon, 17 Oct 2022 22:05:15 +0200 Subject: [PATCH 05/14] fix: Export all animated images as WebP. AVIF is quirky. --- pkg/thumbnail/thumbnail.go | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/pkg/thumbnail/thumbnail.go b/pkg/thumbnail/thumbnail.go index 9fe65153..bfeb0e90 100644 --- a/pkg/thumbnail/thumbnail.go +++ b/pkg/thumbnail/thumbnail.go @@ -22,7 +22,6 @@ var ( animatedThumbnails = []string{ "image/gif", "image/webp", - "image/avif" } cfg config.APIConfig @@ -105,7 +104,7 @@ func BuildAnimatedThumbnail(inputBuf []byte, resp *http.Response) ([]byte, error format := image.Format() // n=-1 is used for animated images to make sure to get all frames and not just the first one. - if format == vips.ImageTypeGIF || format == vips.ImageTypeWEBP || format == vips.ImageTypeAVIF { + if format == vips.ImageTypeGIF || format == vips.ImageTypeWEBP { importParams.NumPages.Set(-1) } @@ -116,11 +115,8 @@ func BuildAnimatedThumbnail(inputBuf []byte, resp *http.Response) ([]byte, error return []byte{}, fmt.Errorf("could not transform image from url: %s", resp.Request.URL) } - // exportParams := vips.NewWebpExportParams() - // exportParams.Quality = 10 - // outputBuf, _, err := image.ExportWebp(exportParams) - - outputBuf, _, err := image.ExportNative() + exportParams := vips.NewWebpExportParams() + outputBuf, _, err := image.ExportWebp(exportParams) if err != nil { return []byte{}, fmt.Errorf("could not export image from url: %s", resp.Request.URL) From dd254338520bc4bff2439df870debf630b3f3494 Mon Sep 17 00:00:00 2001 From: Karar Al-Remahy Date: Mon, 17 Oct 2022 23:54:06 +0200 Subject: [PATCH 06/14] fix: Clarify animated thumbnails is true default Should these configs entries really be called like this? --- config.yaml | 2 +- pkg/config/config.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/config.yaml b/config.yaml index 34148a16..ab446078 100644 --- a/config.yaml +++ b/config.yaml @@ -10,7 +10,7 @@ #max-content-length: 5242880 # When enabled, will attempt to use libvips library to build animated thumbnails. -# Can increase CPU usage and cache storage by a lot. +# Can increase CPU usage and cache storage by a lot. Enabled by default. #enable-animated-thumbnails: true # Maximum width/height pixel size count of the thumbnails sent to the clients. diff --git a/pkg/config/config.go b/pkg/config/config.go index 80ed0cc8..11bce698 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -63,7 +63,7 @@ func init() { pflag.StringP("base-url", "b", "", "Base URL to which clients will make their requests. Useful if the API is proxied through reverse proxy like nginx. Value needs to contain full URL with protocol scheme, e.g. https://braize.pajlada.com/chatterino") pflag.StringP("bind-address", "l", ":1234", "Address to which API will bind and start listening on") pflag.Uint64("max-content-length", 5*1024*1024, "Max content size in bytes - requests with body bigger than this value will be skipped") - pflag.Bool("enable-animated-thumbnails", true, "When enabled, will attempt to use libvips library to build animated thumbnails. Can increase CPU usage and cache storage by a lot") + pflag.Bool("enable-animated-thumbnails", true, "When enabled, will attempt to use libvips library to build animated thumbnails. Can increase CPU usage and cache storage by a lot. Enabled by default") pflag.Uint("max-thumbnail-size", 300, "Maximum width/height pixel size count of the thumbnails sent to the clients.") pflag.String("log-level", "info", "Log level") pflag.Bool("log-development", false, "Enable development logging for warnings and above, this includes stack traces") From 740ffefdd31a0db524558e92a2d2c8de24633211 Mon Sep 17 00:00:00 2001 From: Karar Al-Remahy Date: Tue, 18 Oct 2022 00:51:11 +0200 Subject: [PATCH 07/14] fix: Add comment explaining WebP default export. --- pkg/thumbnail/thumbnail.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/pkg/thumbnail/thumbnail.go b/pkg/thumbnail/thumbnail.go index bfeb0e90..1d4c6707 100644 --- a/pkg/thumbnail/thumbnail.go +++ b/pkg/thumbnail/thumbnail.go @@ -6,7 +6,7 @@ import ( "github.com/Chatterino/api/pkg/config" "github.com/Chatterino/api/pkg/utils" - vips "github.com/davidbyttow/govips/v2/vips" + "github.com/davidbyttow/govips/v2/vips" ) var ( @@ -91,12 +91,9 @@ func BuildAnimatedThumbnail(inputBuf []byte, resp *http.Response) ([]byte, error return []byte{}, fmt.Errorf("could not load image from url: %s", resp.Request.URL) } - // govips has the height & width values in int, which means we're converting uint to int. maxThumbnailSize := int(cfg.MaxThumbnailSize) - // Only resize if the original image has bigger dimensions than maxThumbnailSize if image.Width() <= maxThumbnailSize && image.Height() <= maxThumbnailSize { - // We don't need to resize image nor does it need to be passed through govips. return inputBuf, nil } @@ -115,6 +112,7 @@ func BuildAnimatedThumbnail(inputBuf []byte, resp *http.Response) ([]byte, error return []byte{}, fmt.Errorf("could not transform image from url: %s", resp.Request.URL) } + // We export to WebP by default to save on bandwidth and cache storage. exportParams := vips.NewWebpExportParams() outputBuf, _, err := image.ExportWebp(exportParams) From c65ef790f8c0e3411fed16c391b0a4244d109448 Mon Sep 17 00:00:00 2001 From: Karar Al-Remahy Date: Tue, 18 Oct 2022 00:56:23 +0200 Subject: [PATCH 08/14] docs: Add changelog. --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1cb56eb5..5266eb61 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ ## Unreleased - Breaking: Go version 1.17 is now the minimum required version to build this. (#292) -- Breaking: Thumbnail generation now requires libvips. See [docs/build.md](./docs/build.md) for prerequisite instructions. (#366, #369) +- Breaking: Thumbnail generation now requires libvips. See [docs/build.md](./docs/build.md) for prerequisite instructions. (#366, #369, #312) - Breaking: Resolver caches are now stored in PostgreSQL. See [docs/build.md](./docs/build.md) for prerequisite instructions. (#271) - PDF: Generate customized tooltips for PDF files. (#374) - Twitter: Generate thumbnails with all images of a tweet. (#373) From 01ba6f7c23e928224354c5eb39e58e1d5d6e875a Mon Sep 17 00:00:00 2001 From: Karar Al-Remahy Date: Tue, 18 Oct 2022 09:08:33 +0200 Subject: [PATCH 09/14] docs: Add config field breaking change --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5266eb61..c068d666 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## Unreleased - Breaking: Go version 1.17 is now the minimum required version to build this. (#292) +- Breaking: `enable-lilliput` config renamed to `enable-animated-thumbnails`. (#312) - Breaking: Thumbnail generation now requires libvips. See [docs/build.md](./docs/build.md) for prerequisite instructions. (#366, #369, #312) - Breaking: Resolver caches are now stored in PostgreSQL. See [docs/build.md](./docs/build.md) for prerequisite instructions. (#271) - PDF: Generate customized tooltips for PDF files. (#374) From db9bd3707bfc1ad21b79503a666949c18440ad12 Mon Sep 17 00:00:00 2001 From: Karar Al-Remahy Date: Wed, 19 Oct 2022 01:22:41 +0200 Subject: [PATCH 10/14] fix: Move format variable up Now same location as BuildStaticThumbnail's. --- pkg/thumbnail/thumbnail.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/thumbnail/thumbnail.go b/pkg/thumbnail/thumbnail.go index 27c33304..d92504a3 100644 --- a/pkg/thumbnail/thumbnail.go +++ b/pkg/thumbnail/thumbnail.go @@ -93,13 +93,13 @@ func BuildAnimatedThumbnail(inputBuf []byte, resp *http.Response) ([]byte, error } maxThumbnailSize := int(cfg.MaxThumbnailSize) + format := image.Format() if image.Width() <= maxThumbnailSize && image.Height() <= maxThumbnailSize { return inputBuf, nil } importParams := vips.NewImportParams() - format := image.Format() // n=-1 is used for animated images to make sure to get all frames and not just the first one. if format == vips.ImageTypeGIF || format == vips.ImageTypeWEBP { From 89a8e6d3e349b1d96d3850ce2bc35015b94fda33 Mon Sep 17 00:00:00 2001 From: Karar Al-Remahy Date: Thu, 20 Oct 2022 16:32:16 +0200 Subject: [PATCH 11/14] fix: Use logger per @leon-richardt suggestion --- internal/resolvers/default/thumbnail_loader.go | 2 +- pkg/thumbnail/thumbnail.go | 16 +++++++++++----- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/internal/resolvers/default/thumbnail_loader.go b/internal/resolvers/default/thumbnail_loader.go index 1c0a6520..b48ca507 100644 --- a/internal/resolvers/default/thumbnail_loader.go +++ b/internal/resolvers/default/thumbnail_loader.go @@ -85,7 +85,7 @@ func (l *ThumbnailLoader) Load(ctx context.Context, urlString string, r *http.Re // attempt building an animated image if tryAnimatedThumb { - image, err = thumbnail.BuildAnimatedThumbnail(inputBuf, resp) + image, err = thumbnail.BuildAnimatedThumbnail(ctx, inputBuf, resp) } // fallback to static image if animated image building failed or is disabled diff --git a/pkg/thumbnail/thumbnail.go b/pkg/thumbnail/thumbnail.go index d92504a3..d5747347 100644 --- a/pkg/thumbnail/thumbnail.go +++ b/pkg/thumbnail/thumbnail.go @@ -1,9 +1,11 @@ package thumbnail import ( + "context" "fmt" "net/http" + "github.com/Chatterino/api/internal/logger" "github.com/Chatterino/api/pkg/config" "github.com/Chatterino/api/pkg/utils" "github.com/davidbyttow/govips/v2/vips" @@ -85,11 +87,14 @@ func BuildStaticThumbnail(inputBuf []byte, resp *http.Response) ([]byte, error) return outputBuf, nil } -func BuildAnimatedThumbnail(inputBuf []byte, resp *http.Response) ([]byte, error) { +func BuildAnimatedThumbnail(ctx context.Context, inputBuf []byte, resp *http.Response) ([]byte, error) { + log := logger.FromContext(ctx) + image, err := vips.NewImageFromBuffer(inputBuf) if err != nil { - return []byte{}, fmt.Errorf("could not load image from url: %s", resp.Request.URL) + log.Errorw("could not load image from url: %s", resp.Request.URL, err) + return []byte{}, err } maxThumbnailSize := int(cfg.MaxThumbnailSize) @@ -109,8 +114,8 @@ func BuildAnimatedThumbnail(inputBuf []byte, resp *http.Response) ([]byte, error image, err = vips.LoadThumbnailFromBuffer(inputBuf, maxThumbnailSize, maxThumbnailSize, vips.InterestingAll, vips.SizeDown, importParams) if err != nil { - fmt.Println(err) - return []byte{}, fmt.Errorf("could not transform image from url: %s", resp.Request.URL) + log.Errorw("could not transform image from url: %s", resp.Request.URL, err) + return []byte{}, err } // We export to WebP by default to save on bandwidth and cache storage. @@ -118,7 +123,8 @@ func BuildAnimatedThumbnail(inputBuf []byte, resp *http.Response) ([]byte, error outputBuf, _, err := image.ExportWebp(exportParams) if err != nil { - return []byte{}, fmt.Errorf("could not export image from url: %s", resp.Request.URL) + log.Errorw("could not export image from url %s", resp.Request.URL, err) + return []byte{}, err } return outputBuf, nil From aaa6a3a3e2b93fd7b3b93e09311684cee9daff43 Mon Sep 17 00:00:00 2001 From: Karar Al-Remahy Date: Thu, 20 Oct 2022 16:46:58 +0200 Subject: [PATCH 12/14] fix: Use key value pairs for logger --- pkg/thumbnail/thumbnail.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg/thumbnail/thumbnail.go b/pkg/thumbnail/thumbnail.go index d5747347..04a261f4 100644 --- a/pkg/thumbnail/thumbnail.go +++ b/pkg/thumbnail/thumbnail.go @@ -93,7 +93,7 @@ func BuildAnimatedThumbnail(ctx context.Context, inputBuf []byte, resp *http.Res image, err := vips.NewImageFromBuffer(inputBuf) if err != nil { - log.Errorw("could not load image from url: %s", resp.Request.URL, err) + log.Errorw("could not load image from url", "url", resp.Request.URL, "err", err) return []byte{}, err } @@ -114,7 +114,7 @@ func BuildAnimatedThumbnail(ctx context.Context, inputBuf []byte, resp *http.Res image, err = vips.LoadThumbnailFromBuffer(inputBuf, maxThumbnailSize, maxThumbnailSize, vips.InterestingAll, vips.SizeDown, importParams) if err != nil { - log.Errorw("could not transform image from url: %s", resp.Request.URL, err) + log.Errorw("could not transform image from url", "url", resp.Request.URL, "err", err) return []byte{}, err } @@ -123,7 +123,7 @@ func BuildAnimatedThumbnail(ctx context.Context, inputBuf []byte, resp *http.Res outputBuf, _, err := image.ExportWebp(exportParams) if err != nil { - log.Errorw("could not export image from url %s", resp.Request.URL, err) + log.Errorw("could not export image from url", "url", resp.Request.URL, "err", err) return []byte{}, err } From 41c46c201b4bc274fcf045133de6f6c4a31b0d3a Mon Sep 17 00:00:00 2001 From: Karar Al-Remahy Date: Sat, 29 Oct 2022 12:07:56 +0200 Subject: [PATCH 13/14] fix: Remove comment. --- pkg/thumbnail/thumbnail.go | 1 - 1 file changed, 1 deletion(-) diff --git a/pkg/thumbnail/thumbnail.go b/pkg/thumbnail/thumbnail.go index 04a261f4..efb24122 100644 --- a/pkg/thumbnail/thumbnail.go +++ b/pkg/thumbnail/thumbnail.go @@ -118,7 +118,6 @@ func BuildAnimatedThumbnail(ctx context.Context, inputBuf []byte, resp *http.Res return []byte{}, err } - // We export to WebP by default to save on bandwidth and cache storage. exportParams := vips.NewWebpExportParams() outputBuf, _, err := image.ExportWebp(exportParams) From 0b803ceab04f40204f829fe605608698b3c477d3 Mon Sep 17 00:00:00 2001 From: Karar Al-Remahy Date: Sat, 29 Oct 2022 12:08:19 +0200 Subject: [PATCH 14/14] fix: Re-add readable error for end users --- pkg/thumbnail/thumbnail.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg/thumbnail/thumbnail.go b/pkg/thumbnail/thumbnail.go index efb24122..4dc56977 100644 --- a/pkg/thumbnail/thumbnail.go +++ b/pkg/thumbnail/thumbnail.go @@ -94,7 +94,7 @@ func BuildAnimatedThumbnail(ctx context.Context, inputBuf []byte, resp *http.Res if err != nil { log.Errorw("could not load image from url", "url", resp.Request.URL, "err", err) - return []byte{}, err + return []byte{}, fmt.Errorf("could not load image from url: %s", resp.Request.URL) } maxThumbnailSize := int(cfg.MaxThumbnailSize) @@ -115,7 +115,7 @@ func BuildAnimatedThumbnail(ctx context.Context, inputBuf []byte, resp *http.Res if err != nil { log.Errorw("could not transform image from url", "url", resp.Request.URL, "err", err) - return []byte{}, err + return []byte{}, fmt.Errorf("could not transform image from url: %s", resp.Request.URL) } exportParams := vips.NewWebpExportParams() @@ -123,7 +123,7 @@ func BuildAnimatedThumbnail(ctx context.Context, inputBuf []byte, resp *http.Res if err != nil { log.Errorw("could not export image from url", "url", resp.Request.URL, "err", err) - return []byte{}, err + return []byte{}, fmt.Errorf("could not export image from url: %s", resp.Request.URL) } return outputBuf, nil