2021-05-09 15:07:23 +00:00
|
|
|
package app
|
|
|
|
|
|
|
|
import (
|
2021-05-11 18:22:46 +00:00
|
|
|
"encoding/binary"
|
|
|
|
"image"
|
|
|
|
_ "image/gif"
|
|
|
|
"image/jpeg"
|
|
|
|
_ "image/jpeg"
|
|
|
|
_ "image/png"
|
2021-05-09 15:07:23 +00:00
|
|
|
"net/http"
|
2021-05-10 02:45:40 +00:00
|
|
|
"os"
|
2021-05-09 15:07:23 +00:00
|
|
|
"path/filepath"
|
|
|
|
|
2021-05-11 18:22:46 +00:00
|
|
|
_ "golang.org/x/image/webp"
|
|
|
|
|
2021-05-09 15:07:23 +00:00
|
|
|
"github.com/Damillora/Shioriko/pkg/config"
|
|
|
|
"github.com/Damillora/Shioriko/pkg/database"
|
|
|
|
"github.com/Damillora/Shioriko/pkg/middleware"
|
|
|
|
"github.com/Damillora/Shioriko/pkg/models"
|
2021-05-11 18:22:46 +00:00
|
|
|
"github.com/Damillora/Shioriko/pkg/services"
|
|
|
|
"github.com/corona10/goimagehash"
|
|
|
|
"github.com/disintegration/imaging"
|
2021-05-09 15:07:23 +00:00
|
|
|
"github.com/gin-gonic/gin"
|
|
|
|
"github.com/google/uuid"
|
|
|
|
)
|
|
|
|
|
|
|
|
func InitializeBlobRoutes(g *gin.Engine) {
|
|
|
|
protected := g.Group("/api/blob").Use(middleware.AuthMiddleware())
|
|
|
|
{
|
|
|
|
protected.POST("/upload", uploadBlob)
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
func uploadBlob(c *gin.Context) {
|
|
|
|
dataDir := config.CurrentConfig.DataDirectory
|
|
|
|
// Source
|
|
|
|
file, err := c.FormFile("file")
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
c.JSON(http.StatusBadRequest, models.ErrorResponse{
|
|
|
|
Code: http.StatusBadRequest,
|
|
|
|
Message: err.Error(),
|
|
|
|
})
|
2021-05-11 10:33:22 +00:00
|
|
|
return
|
2021-05-09 15:07:23 +00:00
|
|
|
}
|
2021-05-11 12:21:11 +00:00
|
|
|
|
2021-05-11 10:33:22 +00:00
|
|
|
if err != nil {
|
|
|
|
c.JSON(http.StatusBadRequest, models.ErrorResponse{
|
|
|
|
Code: http.StatusBadRequest,
|
|
|
|
Message: err.Error(),
|
|
|
|
})
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2021-05-11 12:21:11 +00:00
|
|
|
id := uuid.NewString()
|
|
|
|
folder1 := id[0:2]
|
|
|
|
folder2 := id[2:4]
|
|
|
|
if _, err := os.Stat(filepath.Join(dataDir, folder1)); os.IsNotExist(err) {
|
|
|
|
os.Mkdir(filepath.Join(dataDir, folder1), 0755)
|
|
|
|
}
|
|
|
|
if _, err := os.Stat(filepath.Join(dataDir, folder1, folder2)); os.IsNotExist(err) {
|
|
|
|
os.Mkdir(filepath.Join(dataDir, folder1, folder2), 0755)
|
|
|
|
}
|
2021-05-11 10:33:22 +00:00
|
|
|
|
2021-05-11 12:21:11 +00:00
|
|
|
if _, err := os.Stat(filepath.Join(dataDir, "preview", dataDir, folder1)); os.IsNotExist(err) {
|
|
|
|
os.Mkdir(filepath.Join(dataDir, "preview", folder1), 0755)
|
|
|
|
}
|
|
|
|
if _, err := os.Stat(filepath.Join(dataDir, "preview", dataDir, folder1, folder2)); os.IsNotExist(err) {
|
|
|
|
os.Mkdir(filepath.Join(dataDir, "preview", folder1, folder2), 0755)
|
|
|
|
}
|
|
|
|
|
|
|
|
if _, err := os.Stat(filepath.Join(dataDir, "thumbnail", dataDir, folder1)); os.IsNotExist(err) {
|
|
|
|
os.Mkdir(filepath.Join(dataDir, "thumbnail", folder1), 0755)
|
|
|
|
}
|
|
|
|
if _, err := os.Stat(filepath.Join(dataDir, "thumbnail", dataDir, folder1, folder2)); os.IsNotExist(err) {
|
|
|
|
os.Mkdir(filepath.Join(dataDir, "thumbnail", folder1, folder2), 0755)
|
|
|
|
}
|
|
|
|
|
2021-05-11 18:22:46 +00:00
|
|
|
previewFilename := id + ".jpg"
|
|
|
|
previewFilePath := filepath.Join(dataDir, "preview", folder1, folder2, previewFilename)
|
|
|
|
thumbnailFilePath := filepath.Join(dataDir, "thumbnail", folder1, folder2, previewFilename)
|
|
|
|
|
|
|
|
fileObj, _ := file.Open()
|
|
|
|
originalImage, _, err := image.Decode(fileObj)
|
2021-05-11 10:33:22 +00:00
|
|
|
if err != nil {
|
|
|
|
c.JSON(http.StatusBadRequest, models.ErrorResponse{
|
|
|
|
Code: http.StatusBadRequest,
|
|
|
|
Message: err.Error(),
|
|
|
|
})
|
|
|
|
}
|
2021-05-11 18:22:46 +00:00
|
|
|
width := originalImage.Bounds().Dx()
|
|
|
|
height := originalImage.Bounds().Dy()
|
2021-05-11 10:33:22 +00:00
|
|
|
|
2021-05-11 18:22:46 +00:00
|
|
|
hash, err := goimagehash.PerceptionHash(originalImage)
|
2021-05-11 12:21:11 +00:00
|
|
|
if err != nil {
|
|
|
|
c.JSON(http.StatusBadRequest, models.ErrorResponse{
|
|
|
|
Code: http.StatusBadRequest,
|
|
|
|
Message: err.Error(),
|
|
|
|
})
|
2021-05-11 18:22:46 +00:00
|
|
|
return
|
2021-05-10 02:45:40 +00:00
|
|
|
}
|
2021-05-11 18:22:46 +00:00
|
|
|
hashInt := hash.GetHash()
|
|
|
|
|
|
|
|
similarPosts, err := services.SimilaritySearch(hashInt)
|
|
|
|
|
|
|
|
hashSlice := make([]byte, 8)
|
|
|
|
binary.LittleEndian.PutUint64(hashSlice, hashInt)
|
2021-05-11 12:21:11 +00:00
|
|
|
|
2021-05-11 18:22:46 +00:00
|
|
|
previewImage := imaging.Resize(originalImage, 1000, 0, imaging.Lanczos)
|
2021-05-11 12:21:11 +00:00
|
|
|
if err != nil {
|
|
|
|
c.JSON(http.StatusBadRequest, models.ErrorResponse{
|
|
|
|
Code: http.StatusBadRequest,
|
|
|
|
Message: err.Error(),
|
|
|
|
})
|
2021-05-11 18:22:46 +00:00
|
|
|
return
|
2021-05-10 02:45:40 +00:00
|
|
|
}
|
|
|
|
|
2021-05-11 18:22:46 +00:00
|
|
|
thumbnailImage := imaging.Resize(originalImage, 300, 0, imaging.Lanczos)
|
2021-05-11 12:21:11 +00:00
|
|
|
if err != nil {
|
|
|
|
c.JSON(http.StatusBadRequest, models.ErrorResponse{
|
|
|
|
Code: http.StatusBadRequest,
|
|
|
|
Message: err.Error(),
|
|
|
|
})
|
2021-05-11 18:22:46 +00:00
|
|
|
return
|
2021-05-11 12:21:11 +00:00
|
|
|
}
|
2021-05-09 15:07:23 +00:00
|
|
|
|
2021-05-11 18:22:46 +00:00
|
|
|
previewFile, err := os.Create(previewFilePath)
|
2021-05-11 12:21:11 +00:00
|
|
|
if err != nil {
|
|
|
|
c.JSON(http.StatusBadRequest, models.ErrorResponse{
|
|
|
|
Code: http.StatusBadRequest,
|
|
|
|
Message: err.Error(),
|
|
|
|
})
|
2021-05-11 18:22:46 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
thumbnailFile, err := os.Create(thumbnailFilePath)
|
|
|
|
if err != nil {
|
|
|
|
c.JSON(http.StatusBadRequest, models.ErrorResponse{
|
|
|
|
Code: http.StatusBadRequest,
|
|
|
|
Message: err.Error(),
|
|
|
|
})
|
|
|
|
return
|
2021-05-11 12:21:11 +00:00
|
|
|
}
|
|
|
|
|
2021-05-11 18:22:46 +00:00
|
|
|
err = jpeg.Encode(previewFile, previewImage, nil)
|
2021-05-11 12:21:11 +00:00
|
|
|
if err != nil {
|
|
|
|
c.JSON(http.StatusBadRequest, models.ErrorResponse{
|
|
|
|
Code: http.StatusBadRequest,
|
|
|
|
Message: err.Error(),
|
|
|
|
})
|
|
|
|
}
|
2021-05-11 18:22:46 +00:00
|
|
|
err = jpeg.Encode(thumbnailFile, thumbnailImage, nil)
|
2021-05-09 15:07:23 +00:00
|
|
|
if err != nil {
|
|
|
|
c.JSON(http.StatusBadRequest, models.ErrorResponse{
|
|
|
|
Code: http.StatusBadRequest,
|
|
|
|
Message: err.Error(),
|
|
|
|
})
|
2021-05-11 18:22:46 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
filename := id + filepath.Ext(file.Filename)
|
|
|
|
filePath := filepath.Join(dataDir, folder1, folder2, filename)
|
|
|
|
err = c.SaveUploadedFile(file, filePath)
|
|
|
|
if err != nil {
|
|
|
|
c.JSON(http.StatusBadRequest, models.ErrorResponse{
|
|
|
|
Code: http.StatusBadRequest,
|
|
|
|
Message: err.Error(),
|
|
|
|
})
|
|
|
|
return
|
2021-05-09 15:07:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
blob := database.Blob{
|
2021-05-11 12:21:11 +00:00
|
|
|
ID: id,
|
|
|
|
FilePath: filepath.Join(folder1, folder2, filename),
|
|
|
|
PreviewFilePath: filepath.Join("preview", folder1, folder2, previewFilename),
|
|
|
|
ThumbnailFilePath: filepath.Join("thumbnail", folder1, folder2, previewFilename),
|
|
|
|
Width: width,
|
|
|
|
Height: height,
|
2021-05-11 18:22:46 +00:00
|
|
|
Hash1: hashSlice[0:2],
|
|
|
|
Hash2: hashSlice[2:4],
|
|
|
|
Hash3: hashSlice[4:6],
|
|
|
|
Hash4: hashSlice[6:8],
|
2021-05-09 15:07:23 +00:00
|
|
|
}
|
2021-05-11 12:21:11 +00:00
|
|
|
|
2021-05-09 15:07:23 +00:00
|
|
|
database.DB.Create(&blob)
|
|
|
|
|
2021-05-11 18:22:46 +00:00
|
|
|
if len(similarPosts) > 0 {
|
|
|
|
c.JSON(http.StatusOK,
|
|
|
|
models.BlobSimilarResponse{
|
|
|
|
ID: id,
|
|
|
|
Width: width,
|
|
|
|
Height: height,
|
|
|
|
Similar: similarPosts,
|
|
|
|
})
|
|
|
|
return
|
|
|
|
} else {
|
|
|
|
c.JSON(http.StatusOK, models.BlobResponse{
|
|
|
|
ID: id,
|
|
|
|
Width: width,
|
|
|
|
Height: height,
|
|
|
|
})
|
|
|
|
return
|
|
|
|
}
|
2021-05-09 15:07:23 +00:00
|
|
|
}
|