From b48a610e9063c2a1ba6f3615f75113e6e036e604 Mon Sep 17 00:00:00 2001 From: grngxd <36968271+grngxd@users.noreply.github.com> Date: Thu, 31 Jul 2025 22:08:54 +0100 Subject: [PATCH 1/6] add roles --- internal/auth/types.go | 14 ++++++++------ internal/types/errors.go | 25 ++++++++++++------------- 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/internal/auth/types.go b/internal/auth/types.go index 3f2051c..ce06067 100644 --- a/internal/auth/types.go +++ b/internal/auth/types.go @@ -32,12 +32,14 @@ type TokenResponse struct { } type User struct { - ID string `json:"id" gorm:"primaryKey"` - Username string `json:"username"` - Blacklisted bool `json:"blacklisted"` - Email string `json:"email"` - CreatedAt time.Time `json:"created_at"` - HashedApiKey string `json:"hashed_api_key"` + ID string `json:"id" gorm:"primaryKey"` + Username string `json:"username"` + Blacklisted bool `json:"blacklisted"` + Email string `json:"email"` + CreatedAt time.Time `json:"created_at"` + HashedApiKey string `json:"hashed_api_key"` + Role string `json:"role" gorm:"default:'free'"` // free, pro, pro+, admin + SubscriptionExpiresAt time.Time `json:"subscription_expires_at"` } type AvatarDecorationData struct { diff --git a/internal/types/errors.go b/internal/types/errors.go index ec42289..f0d9b4c 100644 --- a/internal/types/errors.go +++ b/internal/types/errors.go @@ -1,23 +1,22 @@ /* - Copyright (C) 2025 hexlocation (hex@iwakura.rip) & grngxd (grng@iwakura.rip) + Copyright (C) 2025 hexlocation (hex@iwakura.rip) & grngxd (grng@iwakura.rip) - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. - You should have received a copy of the GNU General Public License - along with this program. If not, see . + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ package types import ( - "errors" "fmt" "github.com/gin-gonic/gin" @@ -37,7 +36,7 @@ func (e *StereoError) Throw(c *gin.Context, err error) { if err != nil { c.Error(err) } else { - c.Error(errors.New(fmt.Sprintf("Got an error with code: %v", e.Code))) + c.Error(fmt.Errorf("got an error with code: %v", e.Code)) } } From 698f3b1a02ba6b291af67c6df702dd999f7d3acf Mon Sep 17 00:00:00 2001 From: grngxd <36968271+grngxd@users.noreply.github.com> Date: Thu, 31 Jul 2025 22:46:34 +0100 Subject: [PATCH 2/6] revert commit & add meta/:id route --- api.md | 1 + internal/api/routes/files.go | 24 ++++++++++++++++++++++++ internal/auth/types.go | 14 ++++++-------- 3 files changed, 31 insertions(+), 8 deletions(-) diff --git a/api.md b/api.md index 73114d7..a2a865e 100644 --- a/api.md +++ b/api.md @@ -9,4 +9,5 @@ | POST | /api/upload | Upload file | Upload key | | DELETE | /api/:id | Delete file | Upload key | | GET | /api/:id | Get file | Upload key | +| GET | /api/:id/meta | Get file metadata | None | | GET | /api/list | Get a list of uploaded files | Session key | diff --git a/internal/api/routes/files.go b/internal/api/routes/files.go index 3007193..a295936 100644 --- a/internal/api/routes/files.go +++ b/internal/api/routes/files.go @@ -176,6 +176,30 @@ func RegisterFileRoutes(cfg *types.StereoConfig, api *gin.RouterGroup) { c.DataFromReader(200, file.Size, file.Mime, object, nil) }) + api.GET("/meta/:id", func(c *gin.Context) { + fileID := c.Param("id") + fileID = strings.TrimSpace(fileID) + + var file *types.File + id, err := uuid.FromString(fileID) + if err != nil { + types.ErrorInvalidFile.Throw(c, err) + return + } + + if err := cfg.Database.First(&file, id).Error; err != nil { + types.ErrorFileNotFound.Throw(c, err) + return + } + + if file == nil { + types.ErrorFileNotFound.Throw(c, nil) + return + } + + c.JSON(200, file) + }) + api.GET("/list", session.SessionMiddleware(cfg.JWTSecret), func(c *gin.Context) { claims := c.MustGet("claims").(jwt.MapClaims) user := claims["user"].(auth.User) diff --git a/internal/auth/types.go b/internal/auth/types.go index ce06067..a36ac90 100644 --- a/internal/auth/types.go +++ b/internal/auth/types.go @@ -32,14 +32,12 @@ type TokenResponse struct { } type User struct { - ID string `json:"id" gorm:"primaryKey"` - Username string `json:"username"` - Blacklisted bool `json:"blacklisted"` - Email string `json:"email"` - CreatedAt time.Time `json:"created_at"` - HashedApiKey string `json:"hashed_api_key"` - Role string `json:"role" gorm:"default:'free'"` // free, pro, pro+, admin - SubscriptionExpiresAt time.Time `json:"subscription_expires_at"` + ID string `json:"id" gorm:"primaryKey"` + Username string `json:"username"` + Blacklisted bool `json:"blacklisted"` + Email string `json:"email"` + CreatedAt time.Time `json:"created_at"` + HashedApiKey string `json:"hashed_api_key"` } type AvatarDecorationData struct { From 1c5eca8f7249888adf9209442f826f0d35382d8f Mon Sep 17 00:00:00 2001 From: grngxd <36968271+grngxd@users.noreply.github.com> Date: Thu, 31 Jul 2025 22:48:50 +0100 Subject: [PATCH 3/6] oops --- internal/api/routes/files.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/api/routes/files.go b/internal/api/routes/files.go index a295936..2930bdc 100644 --- a/internal/api/routes/files.go +++ b/internal/api/routes/files.go @@ -176,7 +176,7 @@ func RegisterFileRoutes(cfg *types.StereoConfig, api *gin.RouterGroup) { c.DataFromReader(200, file.Size, file.Mime, object, nil) }) - api.GET("/meta/:id", func(c *gin.Context) { + api.GET("/:id/meta", func(c *gin.Context) { fileID := c.Param("id") fileID = strings.TrimSpace(fileID) From bc42a2bb7521f45009cbe498a6ed5b2dc5b36597 Mon Sep 17 00:00:00 2001 From: grngxd <36968271+grngxd@users.noreply.github.com> Date: Fri, 1 Aug 2025 08:33:09 +0100 Subject: [PATCH 4/6] enhance file retrieval: order files by creation date in queries --- internal/api/routes/files.go | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/internal/api/routes/files.go b/internal/api/routes/files.go index 2930bdc..70c3468 100644 --- a/internal/api/routes/files.go +++ b/internal/api/routes/files.go @@ -204,9 +204,10 @@ func RegisterFileRoutes(cfg *types.StereoConfig, api *gin.RouterGroup) { claims := c.MustGet("claims").(jwt.MapClaims) user := claims["user"].(auth.User) + var files []types.File + if c.Query("page") == "" || c.Query("size") == "" { - var files []types.File - if err := cfg.Database.Where("owner = ?", user.ID).Find(&files).Error; err != nil { + if err := cfg.Database.Where("owner = ?", user.ID).Order("created_at DESC").Find(&files).Error; err != nil { types.ErrorDatabase.Throw(c, err) return } @@ -230,12 +231,12 @@ func RegisterFileRoutes(cfg *types.StereoConfig, api *gin.RouterGroup) { return } - var files []types.File offset := (pageNum - 1) * sizeNum if offset < 0 { offset = 0 } - if err := cfg.Database.Where("owner = ?", user.ID).Offset(offset).Limit(sizeNum).Find(&files).Error; err != nil { + + if err := cfg.Database.Where("owner = ?", user.ID).Order("created_at DESC").Offset(offset).Limit(sizeNum).Find(&files).Error; err != nil { types.ErrorDatabase.Throw(c, err) return } From 264739fd76a813e1067d1dac8373bb65fc6662d4 Mon Sep 17 00:00:00 2001 From: grngxd <36968271+grngxd@users.noreply.github.com> Date: Fri, 1 Aug 2025 08:43:25 +0100 Subject: [PATCH 5/6] add blurhash --- go.mod | 1 + go.sum | 3 +++ internal/api/routes/files.go | 16 ++++++++++++++++ internal/types/types.go | 3 ++- 4 files changed, 22 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index c5b1d5e..f0c4941 100644 --- a/go.mod +++ b/go.mod @@ -9,6 +9,7 @@ require ( ) require ( + github.com/bbrks/go-blurhash v1.1.1 // indirect github.com/bytedance/sonic v1.13.2 // indirect github.com/bytedance/sonic/loader v0.2.4 // indirect github.com/cloudwego/base64x v0.1.5 // indirect diff --git a/go.sum b/go.sum index 59c9bb3..6bbd414 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,5 @@ +github.com/bbrks/go-blurhash v1.1.1 h1:uoXOxRPDca9zHYabUTwvS4KnY++KKUbwFo+Yxb8ME4M= +github.com/bbrks/go-blurhash v1.1.1/go.mod h1:lkAsdyXp+EhARcUo85yS2G1o+Sh43I2ebF5togC4bAY= github.com/bytedance/sonic v1.13.2 h1:8/H1FempDZqC4VqjptGo14QQlJx8VdZJegxs6wwfqpQ= github.com/bytedance/sonic v1.13.2/go.mod h1:o68xyaF9u2gvVBuGHPlUVCy+ZfmNNO5ETf1+KgkJhz4= github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= @@ -77,6 +79,7 @@ github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= github.com/lithammer/shortuuid/v4 v4.2.0 h1:LMFOzVB3996a7b8aBuEXxqOBflbfPQAiVzkIcHO0h8c= github.com/lithammer/shortuuid/v4 v4.2.0/go.mod h1:D5noHZ2oFw/YaKCfGy0YxyE7M0wMbezmMjPdhyEFe6Y= +github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-sqlite3 v1.14.28 h1:ThEiQrnbtumT+QMknw63Befp/ce/nUPgBPMlRFEum7A= diff --git a/internal/api/routes/files.go b/internal/api/routes/files.go index 70c3468..fbe6efa 100644 --- a/internal/api/routes/files.go +++ b/internal/api/routes/files.go @@ -24,6 +24,9 @@ import ( "strings" "time" + "image" + + "github.com/bbrks/go-blurhash" "github.com/gin-gonic/gin" "github.com/gofrs/uuid" "github.com/golang-jwt/jwt/v5" @@ -84,12 +87,25 @@ func RegisterFileRoutes(cfg *types.StereoConfig, api *gin.RouterGroup) { return } + img, _, err := image.Decode(bytes.NewReader(buf)) + if err != nil { + types.ErrorInvalidFile.Throw(c, err) + return + } + + hash, err := blurhash.Encode(4, 3, img) + if err != nil { + types.ErrorInvalidFile.Throw(c, err) + return + } + fileMeta := types.File{ Owner: uid, Name: file.Filename, CreatedAt: time.Now(), Size: int64(len(buf)), Mime: fileType.MIME.Value, + Blurhash: hash, } if err := cfg.Database.Create(&fileMeta).Error; err != nil { diff --git a/internal/types/types.go b/internal/types/types.go index 535be51..0db5951 100644 --- a/internal/types/types.go +++ b/internal/types/types.go @@ -53,7 +53,8 @@ type File struct { Owner string `gorm:"not null;index"` Size int64 `gorm:"not null;type:bigint"` CreatedAt time.Time `gorm:"autoCreateTime"` - Mime string + Mime string ` gorm:"type:text"` + Blurhash string `gorm:"type:text"` } func (f *File) BeforeCreate(tx *gorm.DB) (err error) { From 997774c5de63a5dcac6f33d20f84268d389ae71a Mon Sep 17 00:00:00 2001 From: grngxd <36968271+grngxd@users.noreply.github.com> Date: Fri, 1 Aug 2025 10:45:56 +0100 Subject: [PATCH 6/6] use thumbhash instead of blurhash --- go.mod | 20 +++++++++---------- go.sum | 10 ++-------- internal/api/routes/files.go | 38 ++++++++++++++++++++++-------------- internal/types/types.go | 6 ++++-- 4 files changed, 38 insertions(+), 36 deletions(-) diff --git a/go.mod b/go.mod index f0c4941..380ea25 100644 --- a/go.mod +++ b/go.mod @@ -3,17 +3,24 @@ module stereo.cat/backend go 1.24.2 require ( + github.com/cristalhq/base64 v0.1.2 + github.com/galdor/go-thumbhash v1.0.0 github.com/gin-gonic/gin v1.10.0 + github.com/gofrs/uuid v4.4.0+incompatible + github.com/golang-jwt/jwt/v5 v5.2.2 + github.com/h2non/filetype v1.1.3 github.com/joho/godotenv v1.5.1 + github.com/minio/minio-go/v7 v7.0.93 + golang.org/x/crypto v0.37.0 + gorm.io/driver/postgres v1.5.11 + gorm.io/driver/sqlite v1.5.7 gorm.io/gorm v1.26.0 ) require ( - github.com/bbrks/go-blurhash v1.1.1 // indirect github.com/bytedance/sonic v1.13.2 // indirect github.com/bytedance/sonic/loader v0.2.4 // indirect github.com/cloudwego/base64x v0.1.5 // indirect - github.com/cristalhq/base64 v0.1.2 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/gabriel-vasile/mimetype v1.4.9 // indirect github.com/gin-contrib/sse v1.1.0 // indirect @@ -22,10 +29,7 @@ require ( github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/validator/v10 v10.26.0 // indirect github.com/goccy/go-json v0.10.5 // indirect - github.com/gofrs/uuid v4.4.0+incompatible // indirect - github.com/golang-jwt/jwt/v5 v5.2.2 // indirect github.com/google/uuid v1.6.0 // indirect - github.com/h2non/filetype v1.1.3 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect github.com/jackc/pgx/v5 v5.7.4 // indirect @@ -37,12 +41,10 @@ require ( github.com/klauspost/cpuid/v2 v2.2.10 // indirect github.com/kr/pretty v0.3.1 // indirect github.com/leodido/go-urn v1.4.0 // indirect - github.com/lithammer/shortuuid/v4 v4.2.0 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-sqlite3 v1.14.28 // indirect github.com/minio/crc64nvme v1.0.1 // indirect github.com/minio/md5-simd v1.1.2 // indirect - github.com/minio/minio-go/v7 v7.0.93 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/pelletier/go-toml/v2 v2.2.4 // indirect @@ -53,14 +55,10 @@ require ( github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.12 // indirect golang.org/x/arch v0.16.0 // indirect - golang.org/x/crypto v0.37.0 // indirect golang.org/x/net v0.39.0 // indirect golang.org/x/sync v0.14.0 // indirect golang.org/x/sys v0.32.0 // indirect golang.org/x/text v0.24.0 // indirect google.golang.org/protobuf v1.36.6 // indirect - gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - gorm.io/driver/postgres v1.5.11 // indirect - gorm.io/driver/sqlite v1.5.7 // indirect ) diff --git a/go.sum b/go.sum index 6bbd414..fe17815 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,3 @@ -github.com/bbrks/go-blurhash v1.1.1 h1:uoXOxRPDca9zHYabUTwvS4KnY++KKUbwFo+Yxb8ME4M= -github.com/bbrks/go-blurhash v1.1.1/go.mod h1:lkAsdyXp+EhARcUo85yS2G1o+Sh43I2ebF5togC4bAY= github.com/bytedance/sonic v1.13.2 h1:8/H1FempDZqC4VqjptGo14QQlJx8VdZJegxs6wwfqpQ= github.com/bytedance/sonic v1.13.2/go.mod h1:o68xyaF9u2gvVBuGHPlUVCy+ZfmNNO5ETf1+KgkJhz4= github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= @@ -18,6 +16,8 @@ github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkp github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/gabriel-vasile/mimetype v1.4.9 h1:5k+WDwEsD9eTLL8Tz3L0VnmVh9QxGjRmjBvAG7U/oYY= github.com/gabriel-vasile/mimetype v1.4.9/go.mod h1:WnSQhFKJuBlRyLiKohA/2DtIlPFAbguNaG7QCHcyGok= +github.com/galdor/go-thumbhash v1.0.0 h1:Q7xSnaDvSC91SuNmQI94JuUVHva29FDdA4/PkV0EHjU= +github.com/galdor/go-thumbhash v1.0.0/go.mod h1:gEK2wZqIxS2W4mXNf48lPl6HWjX0vWsH1LpK/cU74Ho= github.com/gin-contrib/sse v1.1.0 h1:n0w2GMuUpWDVp7qSpvze6fAu9iRxJY4Hmj6AmBOU05w= github.com/gin-contrib/sse v1.1.0/go.mod h1:hxRZ5gVpWMT7Z0B0gSNYqqsSCNIJMjzvm6fqCz9vjwM= github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU= @@ -68,18 +68,12 @@ github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa02 github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE= github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= -github.com/lithammer/shortuuid/v4 v4.2.0 h1:LMFOzVB3996a7b8aBuEXxqOBflbfPQAiVzkIcHO0h8c= -github.com/lithammer/shortuuid/v4 v4.2.0/go.mod h1:D5noHZ2oFw/YaKCfGy0YxyE7M0wMbezmMjPdhyEFe6Y= -github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-sqlite3 v1.14.28 h1:ThEiQrnbtumT+QMknw63Befp/ce/nUPgBPMlRFEum7A= diff --git a/internal/api/routes/files.go b/internal/api/routes/files.go index fbe6efa..595c94f 100644 --- a/internal/api/routes/files.go +++ b/internal/api/routes/files.go @@ -19,14 +19,18 @@ package routes import ( "bytes" + "encoding/base64" "io" "strconv" "strings" "time" "image" + _ "image/gif" + _ "image/jpeg" + _ "image/png" - "github.com/bbrks/go-blurhash" + "github.com/galdor/go-thumbhash" "github.com/gin-gonic/gin" "github.com/gofrs/uuid" "github.com/golang-jwt/jwt/v5" @@ -81,31 +85,35 @@ func RegisterFileRoutes(cfg *types.StereoConfig, api *gin.RouterGroup) { } fileType, err := filetype.Match(buf) - - if err != nil { - types.ErrorReaderOpen.Throw(c, err) - return - } - - img, _, err := image.Decode(bytes.NewReader(buf)) if err != nil { types.ErrorInvalidFile.Throw(c, err) return } - hash, err := blurhash.Encode(4, 3, img) - if err != nil { - types.ErrorInvalidFile.Throw(c, err) - return - } + mime := fileType.MIME.Value fileMeta := types.File{ Owner: uid, Name: file.Filename, CreatedAt: time.Now(), Size: int64(len(buf)), - Mime: fileType.MIME.Value, - Blurhash: hash, + Mime: mime, + } + + if filetype.IsImage(buf) { + img, _, err := image.Decode(bytes.NewReader(buf)) + if err != nil { + types.ErrorInvalidFile.Throw(c, err) + return + } + + hashBytes := thumbhash.EncodeImage(img) + // encode the byte[] into a string + hash := base64.StdEncoding.EncodeToString(hashBytes) + + fileMeta.Hash = hash + fileMeta.Width = img.Bounds().Dx() + fileMeta.Height = img.Bounds().Dy() } if err := cfg.Database.Create(&fileMeta).Error; err != nil { diff --git a/internal/types/types.go b/internal/types/types.go index 0db5951..0395fcb 100644 --- a/internal/types/types.go +++ b/internal/types/types.go @@ -53,8 +53,10 @@ type File struct { Owner string `gorm:"not null;index"` Size int64 `gorm:"not null;type:bigint"` CreatedAt time.Time `gorm:"autoCreateTime"` - Mime string ` gorm:"type:text"` - Blurhash string `gorm:"type:text"` + Mime string `gorm:"type:text"` + Hash string `gorm:"type:text"` + Width int + Height int } func (f *File) BeforeCreate(tx *gorm.DB) (err error) {