diff --git a/config_test.go b/config_test.go deleted file mode 100644 index 92da3be..0000000 --- a/config_test.go +++ /dev/null @@ -1,17 +0,0 @@ -package imagorvideoextended - -import ( - "github.com/cshum/imagor" - "github.com/cshum/imagor/config" - "github.com/stretchr/testify/assert" - "testing" -) - -func TestConfig(t *testing.T) { - srv := config.CreateServer([]string{ - "-ffmpeg-fallback-image", "https://foo.com/bar.jpg", - }, Config) - app := srv.App.(*imagor.Imagor) - processor := app.Processors[0].(*Processor) - assert.Equal(t, "https://foo.com/bar.jpg", processor.FallbackImage) -} diff --git a/processor.go b/processor.go index bf6fe93..0ceb2a7 100644 --- a/processor.go +++ b/processor.go @@ -2,12 +2,14 @@ package imagorvideoextended import ( "context" + "crypto/sha256" "github.com/antchfx/htmlquery" "github.com/cshum/imagor" "github.com/cshum/imagor/imagorpath" "github.com/gabriel-vasile/mimetype" "go.uber.org/zap" "io" + "os" "strings" ) @@ -39,6 +41,18 @@ func (p *Processor) Shutdown(_ context.Context) error { return nil } +func subThumbnail(url string) string { + key := os.Getenv("IMAGOR_SECRET") + params := imagorpath.Params{ + Image: url, + FitIn: true, + Width: 400, + Height: 400, + } + path := imagorpath.Generate(params, imagorpath.NewHMACSigner(sha256.New, 0, key)) + return path +} + // Process implements imagor.Processor interface func (p *Processor) Process(ctx context.Context, in *imagor.Blob, params imagorpath.Params, load imagor.LoadFunc) (out *imagor.Blob, err error) { defer func() { @@ -57,6 +71,7 @@ func (p *Processor) Process(ctx context.Context, in *imagor.Blob, params imagorp } } }() + var mime = mimetype.Detect(in.Sniff()) if typ := mime.String(); !strings.HasPrefix(typ, "text/html") { @@ -103,7 +118,7 @@ func (p *Processor) Process(ctx context.Context, in *imagor.Blob, params imagorp case "og:image": fallthrough case "twitter:image:src": - meta.Image = val + meta.Image = subThumbnail(val) break case "og:title": diff --git a/processor_test.go b/processor_test.go deleted file mode 100644 index c3fc0b0..0000000 --- a/processor_test.go +++ /dev/null @@ -1,161 +0,0 @@ -package imagorvideoextended - -import ( - "context" - "fmt" - "github.com/cshum/imagor" - "github.com/cshum/imagor/imagorpath" - "github.com/cshum/imagor/storage/filestorage" - "github.com/cshum/imagor/vips" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "go.uber.org/zap" - "io" - "net/http" - "net/http/httptest" - "os" - "path/filepath" - "reflect" - "runtime" - "strings" - "testing" -) - -var testDataDir string - -func init() { - _, b, _, _ := runtime.Caller(0) - testDataDir = filepath.Join(filepath.Dir(b), "./testdata") -} - -type test struct { - name string - path string - expectCode int -} - -func TestProcessor(t *testing.T) { - v := vips.NewProcessor(vips.WithDebug(true)) - require.NoError(t, v.Startup(context.Background())) - t.Cleanup(func() { - require.NoError(t, v.Shutdown(context.Background())) - }) - doGoldenTests(t, filepath.Join(testDataDir, "golden/result"), []test{ - {name: "mkv", path: "fit-in/100x100/everybody-betray-me.mkv"}, - {name: "mkv specific frame", path: "fit-in/100x100/filters:frame(3)/everybody-betray-me.mkv"}, - {name: "mkv specific max_frames", path: "fit-in/100x100/filters:max_frames(6)/everybody-betray-me.mkv"}, - {name: "mkv specific frame exceeded", path: "fit-in/100x100/filters:frame(99999)/everybody-betray-me.mkv"}, - {name: "mkv meta max_frames", path: "meta/filters:max_frames()/everybody-betray-me.mkv"}, - {name: "mkv meta max_frames 6", path: "meta/filters:max_frames(6)/everybody-betray-me.mkv"}, - {name: "mkv meta", path: "meta/everybody-betray-me.mkv"}, - {name: "mp4", path: "200x100/schizo_0.mp4"}, - {name: "mp4 orient 90", path: "220x100/schizo_90.mp4"}, - {name: "mp4 orient 180", path: "200x100/schizo_180.mp4"}, - {name: "mp4 orient 270", path: "200x100/schizo_270.mp4"}, - {name: "image", path: "fit-in/100x100/demo.png"}, - {name: "alpha", path: "fit-in/filters:format(png)/alpha-webm.webm"}, - {name: "alpha frame duration", path: "500x/filters:frame(5s):format(png)/alpha-webm.webm"}, - {name: "alpha frame position", path: "500x/filters:frame(0.5):format(png)/alpha-webm.webm"}, - {name: "alpha seek duration", path: "500x/filters:seek(5s):format(png)/alpha-webm.webm"}, - {name: "alpha seek position", path: "500x/filters:seek(0.5):format(png)/alpha-webm.webm"}, - {name: "corrupted", path: "fit-in/100x100/corrupt/everybody-betray-me.mkv", expectCode: 406}, - {name: "no cover meta", path: "meta/no_cover.mp3"}, - {name: "no cover 406", path: "fit-in/100x100/no_cover.mp3", expectCode: 406}, - }, WithDebug(true), WithLogger(zap.NewExample())) - doGoldenTests(t, filepath.Join(testDataDir, "golden/result-fallback-image"), []test{ - {name: "corrupted with fallback image", path: "fit-in/100x100/corrupt/everybody-betray-me.mkv", expectCode: 406}, - {name: "corrupted with fallback image", path: "filters:seek(0.1)/no_cover.mp3", expectCode: 406}, - }, WithDebug(false), WithLogger(zap.NewExample()), WithFallbackImage("demo.png")) -} - -func doGoldenTests(t *testing.T, resultDir string, tests []test, opts ...Option) { - resStorage := filestorage.New(resultDir, - filestorage.WithSaveErrIfExists(true)) - fileLoader := filestorage.New(testDataDir) - loaders := []imagor.Loader{ - fileLoader, - loaderFunc(func(r *http.Request, image string) (blob *imagor.Blob, err error) { - image, _ = fileLoader.Path(image) - return imagor.NewBlob(func() (reader io.ReadCloser, size int64, err error) { - // force read full file by 0 size - reader, err = os.Open(image) - return - }), nil - }), - } - for i, loader := range loaders { - app := imagor.New( - imagor.WithLoaders(loaderFunc(func(r *http.Request, image string) (blob *imagor.Blob, err error) { - if strings.HasPrefix(image, "corrupt/") { - image, _ = fileLoader.Path(strings.TrimPrefix(image, "corrupt/")) - return imagor.NewBlob(func() (reader io.ReadCloser, size int64, err error) { - file, err := os.Open(image) - // truncate so it corrupt - reader = &readCloser{ - Reader: io.LimitReader(file, 1024), - Closer: file, - } - return - }), nil - } - return nil, imagor.ErrNotFound - }), loader), - imagor.WithUnsafe(true), - imagor.WithDebug(true), - imagor.WithLogger(zap.NewExample()), - imagor.WithProcessors(NewProcessor(opts...), vips.NewProcessor()), - ) - require.NoError(t, app.Startup(context.Background())) - t.Cleanup(func() { - assert.NoError(t, app.Shutdown(context.Background())) - }) - for _, tt := range tests { - t.Run(fmt.Sprintf("%s-%d", tt.name, i+1), func(t *testing.T) { - w := httptest.NewRecorder() - ctx, cancel := context.WithCancel(context.Background()) - req := httptest.NewRequest( - http.MethodGet, fmt.Sprintf("/unsafe/%s", tt.path), nil).WithContext(ctx) - app.ServeHTTP(w, req) - cancel() - if tt.expectCode == 0 { - assert.Equal(t, 200, w.Code) - } else { - assert.Equal(t, tt.expectCode, w.Code) - } - b := imagor.NewBlobFromBytes(w.Body.Bytes()) - _ = resStorage.Put(context.Background(), tt.path, b) - path := filepath.Join(resultDir, imagorpath.Normalize(tt.path, nil)) - bc := imagor.NewBlobFromFile(path) - buf, err := bc.ReadAll() - require.NoError(t, err) - if reflect.DeepEqual(buf, w.Body.Bytes()) { - return - } - img1, err := vips.LoadImageFromBuffer(buf, nil) - require.NoError(t, err) - img2, err := vips.LoadImageFromBuffer(w.Body.Bytes(), nil) - require.NoError(t, err) - require.Equal(t, img1.Width(), img2.Width(), "width mismatch") - require.Equal(t, img1.Height(), img2.Height(), "height mismatch") - buf1, err := img1.ExportWebp(nil) - require.NoError(t, err) - buf2, err := img2.ExportWebp(nil) - require.NoError(t, err) - require.True(t, reflect.DeepEqual(buf1, buf2), "image mismatch") - }) - } - - } - -} - -type loaderFunc func(r *http.Request, image string) (blob *imagor.Blob, err error) - -func (f loaderFunc) Get(r *http.Request, image string) (*imagor.Blob, error) { - return f(r, image) -} - -type readCloser struct { - io.Reader - io.Closer -}