Skip to content

Commit

Permalink
feat: Enable static thumbnail generation on Windows (#369)
Browse files Browse the repository at this point in the history
  • Loading branch information
KararTY authored Oct 10, 2022
1 parent 98d0c30 commit f963f43
Show file tree
Hide file tree
Showing 6 changed files with 66 additions and 64 deletions.
11 changes: 11 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,17 @@ jobs:
if: matrix.os == 'macos-latest'
run: brew install vips

- name: Get external dependencies (Windows)
if: matrix.os == 'windows-latest'
run: |
choco upgrade -y pkgconfiglite
Invoke-WebRequest -Uri https://github.com/libvips/build-win64-mxe/releases/download/v8.13.2/vips-dev-w64-web-8.13.2-static.zip -OutFile .\vips-dev.zip
Expand-Archive -Path .\vips-dev.zip -DestinationPath .\
$env:VIPS_PATH=$(Resolve-Path ".\vips-dev-8.13" | select -ExpandProperty Path)
"VIPS_PATH=$(Resolve-Path ".\vips-dev-8.13" | select -ExpandProperty Path)" >> $env:GITHUB_ENV
"PKG_CONFIG_PATH=$env:VIPS_PATH\lib\pkgconfig" >> $env:GITHUB_ENV
"$env:VIPS_PATH\bin" >> $env:GITHUB_PATH
- name: Get Go dependencies
run: |
go get -v -t -d ./...
Expand Down
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
- Breaking: Thumbnail generation now requires libvips. See [docs/build.md](./docs/build.md) for prerequisite instructions. (#366, #369)
- Breaking: Resolver caches are now stored in PostgreSQL. See [docs/build.md](./docs/build.md) for prerequisite instructions. (#271)
- YouTube: Added support for 'YouTube shorts' URLs. (#299)
- Fix: SevenTV emotes now resolve correctly. (#281, #288, #307)
Expand Down
9 changes: 8 additions & 1 deletion docs/build.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,17 @@
## Prerequisites

1. Resolved links are stored in PostgreSQL, so you must have PostgreSQL installed and accessible for the user running the API. For Ubuntu, you would install it with `sudo apt install postgresql`, create a DB user for your system user (`sudo -upostgres createuser pajlada`), then create a db for the api (`sudo -upostgres createdb chatterino-api --owner pajlada`). Make sure to edit `dsn` in your [configuration](./config.md). Example, using the details above, `dsn:"host=/var/run/postgresql user=pajlada database=chatterino-api"`.
2. You must have [`libvips`](https://github.com/libvips/libvips) >=8.12.0 installed for thumbnail generation. (Linux-exclusive)
2. You must have [`libvips`](https://github.com/libvips/libvips) >=8.12.0 installed for thumbnail generation.

On Ubuntu 22.04, this can be done with `sudo apt install libvips libvips-dev`.
Different distros or releases may require adding a PPA or building and installing from source.

For Windows when getting the [Windows binaries](https://github.com/libvips/build-win64-mxe/releases/latest) from the libvips link above make sure to get the ones suffixed with "-static".
Install pkg-config via choco `choco upgrade -y pkgconfiglite` and setup the following environment variables:
`VIPS_PATH` to the directory where vips-dev is downloaded and extracted,
`PKG_CONFIG_PATH` to `%VIPS_PATH%\lib\pkgconfig`
and append `%VIPS_PATH%\bin` to your `Path` environment variable.

## Build

1. Clone the repo: `git pull https://github.com/Chatterino/api.git`
Expand Down
46 changes: 46 additions & 0 deletions pkg/thumbnail/thumbnail.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
package thumbnail

import (
"fmt"
"net/http"

"github.com/Chatterino/api/pkg/config"
"github.com/Chatterino/api/pkg/utils"
vips "github.com/davidbyttow/govips/v2/vips"
)

var (
Expand All @@ -19,3 +23,45 @@ func IsSupportedThumbnailType(contentType string) bool {
func IsAnimatedThumbnailType(contentType string) bool {
return utils.Contains(animatedThumbnails, contentType)
}

func InitializeConfig(passedCfg config.APIConfig) {
cfg = passedCfg
vips.Startup(nil)
}

func Shutdown() {
vips.Shutdown()
}

func BuildStaticThumbnail(inputBuf []byte, resp *http.Response) ([]byte, error) {
image, err := vips.NewImageFromBuffer(inputBuf)

// 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()

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)

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
}
45 changes: 0 additions & 45 deletions pkg/thumbnail/thumbnail_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,6 @@ import (
"net/http"
"strings"

"github.com/Chatterino/api/pkg/config"

vips "github.com/davidbyttow/govips/v2/vips"
"github.com/discord/lilliput"
)

Expand All @@ -20,15 +17,6 @@ var encodeOptions = map[string]map[int]int{
".webp": {lilliput.WebpQuality: 85},
}

func InitializeConfig(passedCfg config.APIConfig) {
cfg = passedCfg
vips.Startup(nil)
}

func Shutdown() {
vips.Shutdown()
}

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)
Expand Down Expand Up @@ -106,36 +94,3 @@ func BuildAnimatedThumbnail(inputBuf []byte, resp *http.Response) ([]byte, error

return outputImg, nil
}

func BuildStaticThumbnail(inputBuf []byte, resp *http.Response) ([]byte, error) {
image, err := vips.NewImageFromBuffer(inputBuf)

// 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()

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)

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
}
17 changes: 0 additions & 17 deletions pkg/thumbnail/thumbnail_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,9 @@ package thumbnail
import (
"errors"
"net/http"

"github.com/Chatterino/api/pkg/config"
)

func InitializeConfig(passedCfg config.APIConfig) {
cfg = passedCfg
}

func Shutdown() {
// Nothing to shut down on Windows
}

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")
}

func BuildStaticThumbnail(inputBuf []byte, resp *http.Response) ([]byte, error) {
// govips can run on Windows with the proper setup. If you would like to contribute Windows
// support, see https://github.com/davidbyttow/govips#windows and open a PR at
// https://github.com/Chatterino/api/pulls.
return nil, errors.New("cannot build static thumbnails on windows")
}

0 comments on commit f963f43

Please sign in to comment.