fonchain-fiee/pkg/service/upload/upload.go
2025-02-22 15:31:21 +08:00

323 lines
9.5 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package upload
import (
"bytes"
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"fonchain-fiee/pkg/config"
"fonchain-fiee/pkg/e"
"fonchain-fiee/pkg/logic"
"fonchain-fiee/pkg/model"
"fonchain-fiee/pkg/service"
"fonchain-fiee/pkg/utils"
"github.com/disintegration/imaging"
"github.com/fonchain_enterprise/utils/objstorage"
"github.com/gin-gonic/gin"
uuid "github.com/satori/go.uuid"
"io"
ffmpeg "github.com/u2takey/ffmpeg-go"
"go.uber.org/zap"
"io/ioutil"
"mime/multipart"
"net/url"
"os"
"path"
"path/filepath"
"strconv"
"strings"
)
const (
MediaPath = "./runtime/"
RouteType = "static/"
VideoType = "video"
ImageType = "image"
PngType = "png"
PdfType = "pdf"
ArtworkFilePath = "artwork"
ArtworkChunkBasePath = "./runtime/tmp/artworks"
)
func UploadImg(c *gin.Context) {
var err error
var filename string
var fileFullName string
source := c.PostForm("source")
mask := c.PostForm("mask")
action := c.PostForm("action")
defineFileName := c.PostForm("defineFileName")
urlParam := c.PostForm("urlParam")
if mask == "" {
mask = "default"
}
mediaType := c.PostForm("type")
zap.L().Info("UploadImg 1", zap.Any("mask", mask))
var BasePath string
if mediaType == "" || mediaType == ImageType {
mediaType = ImageType
}
BasePath = fmt.Sprintf("%s%s", MediaPath, mediaType)
//BaseRoute = fmt.Sprintf("%s%s", RouteType, mediaType)
var isCompress int
if cStr, ok := c.GetPostForm("is_compress"); ok {
var errS error
isCompress, errS = strconv.Atoi(cStr)
if errS != nil {
service.Error(c, err)
return
}
}
zap.L().Info("UploadImg 2 ", zap.Any("mask", mask))
// 检验参数
if mask == "" || source == "" {
service.Error(c, err)
return
}
file, err := c.FormFile("file")
// 检验文件
if err != nil {
zap.L().Error("Upload FormFile err", zap.Error(err))
service.Error(c, err)
return
}
//logger.Errorf("UploadImg 3 %+v", mask)
// 判断是不是视频或者需要压缩
var oriUrl string
if isCompress != 1 && mediaType != "video" && action == "" {
oriUrl, err = quickBos(file, mediaType, mask, source, defineFileName)
if err != nil {
service.Error(c, err)
return
}
if urlParam != "" {
oriUrl = fmt.Sprintf("%s?%s", oriUrl, urlParam)
}
service.Success(c, oriUrl)
return
}
//创建文件名
fileExt := strings.ToLower(path.Ext(file.Filename))
if defineFileName != "" {
fileFullName = defineFileName
} else {
newUu, _err := uuid.NewV4()
if _err != nil {
service.Error(c, err)
return
}
filename = newUu.String()
fileFullName = fmt.Sprintf("%s%s", filename, fileExt)
}
//检测文件夹 不存在就创建
imgPath := fmt.Sprintf("%s/%s/%s", BasePath, source, mask)
_, err = utils.CheckDirPath(imgPath, true)
if err != nil {
service.Error(c, err)
return
}
dst := fmt.Sprintf("%s/%s", imgPath, fileFullName)
// 保存文件至指定路径
err = c.SaveUploadedFile(file, dst)
if err != nil {
service.Error(c, err)
return
}
if action == model.ImgActionRotate {
fileFullName = fmt.Sprintf("%s%s", filename, fileExt)
newDst := fmt.Sprintf("%s/%s_rotate%v", imgPath, filename, fileExt)
if err = logic.MakeThumbnail(dst, newDst); err != nil {
//ResponseQuickMsg(c, e.Failed, e.GetMsg(e.ERROR_ROTATE_IMG), nil)
//return
} else {
_ = os.Remove(dst)
dst = newDst
}
}
//localUrl := fmt.Sprintf("%s/%s/%s/%s/%s", config.ServerDM, BaseRoute, source, mask, fileFullName)
var data map[string]string = make(map[string]string, 2)
//data["ori_url"] = localUrl
if int32(isCompress) == 1 {
//压缩图片并存储在原图路径命名格式xx.jpg_small.jpg
fileFullName = fmt.Sprintf("%s_small%s", filename, fileExt)
newDst := fmt.Sprintf("%s/%s", imgPath, fileFullName)
//compressUrl := fmt.Sprintf("%s/%s/%s/%s/%s", config.ServerDM, BaseRoute, source, mask, fileFullName)
err = utils.CompressJPG(dst, newDst)
compressUrl, err := PutBos(newDst, mediaType, true)
if err != nil {
service.Error(c, err)
return
}
data["compress_url"] = compressUrl
}
// 如果是视频需要截图图片做封面
if mediaType == VideoType {
videoCover := fmt.Sprintf("%s/%s", imgPath, filename)
_, err = GetSnapshot(dst, videoCover, 1)
if err != nil {
zap.L().Error("GetSnapshot err", zap.Error(err))
service.Error(c, err)
return
}
zap.L().Info("UploadImg 8.1 videoCover", zap.Any("videoCover", videoCover))
//data["cover_url"] = fmt.Sprintf("%s/%s/%s/%s/%s", config.ServerDM, BaseRoute, source, mask, fmt.Sprintf("%s.%s", filename, PngType))
coverUrl, err := PutBos(videoCover+"."+PngType, mediaType, true)
if urlParam != "" {
coverUrl = fmt.Sprintf("%s?%s", coverUrl, urlParam)
}
data["cover_url"] = coverUrl
if err != nil {
zap.L().Error("Upload GetSnapshot err", zap.Error(err))
service.Error(c, err)
return
}
//ResponseQuickMsg(c, e.Ok, e.GetMsg(e.SUCCESS), data)
//return
}
ossUrl, err := PutBos(dst, mediaType, true)
if err != nil {
service.Error(c, err)
return
}
if urlParam != "" {
ossUrl = fmt.Sprintf("%s?%s", ossUrl, urlParam)
}
data["ori_url"] = ossUrl
service.Success(c, data)
return
}
func quickBos(file *multipart.FileHeader, mediaType string, mask string, source string, defineFileName string) (url string, err error) {
newFile, _ := file.Open()
var filename string
defer newFile.Close()
if defineFileName != "" {
filename = defineFileName
} else {
uuids, _ := uuid.NewV4()
filename = uuids.String()
filename = fmt.Sprintf("%s%s", filename, filepath.Ext(file.Filename))
}
filePath := fmt.Sprintf("%s/%s/%s/%s", mediaType, mask, source, filename)
fileBytes, _ := ioutil.ReadAll(newFile)
if mediaType == "image" {
if err = BaiduCheckImage(fileBytes); err != nil {
return
}
}
var objectName string = fmt.Sprintf("%s/%s/%s", config.ConfigData.Oss.BaseDir, config.Env, filePath)
BOSClient, _ := objstorage.NewOSS(config.ConfigData.Oss.AccessKeyId, config.ConfigData.Oss.AccessKeySecret, config.ConfigData.Oss.Endpoint)
_, err = BOSClient.PutObjectFromBytes(config.ConfigData.Oss.BucketName, objectName, fileBytes)
if err != nil {
//logger.Errorf("quickOss err", err)
return
}
//url = fmt.Sprintf("%s%s%s/%s", config.BosHttp, config.BosBucketName, config.BosUrl, objectName)
url = fmt.Sprintf("%s/%s", config.ConfigData.Oss.CdnHost, objectName)
return
}
// BaiduCheckImage 图片鉴黄
func BaiduCheckImage(imageByte []byte) (err error) {
return
var (
accesstoken string
response string
)
sourcestring := base64.StdEncoding.EncodeToString(imageByte)
if accesstoken, err = logic.GetImageAccessToken(); err != nil {
return err
}
host := "https://aip.baidubce.com/rest/2.0/solution/v1/img_censor/v2/user_defined?access_token=[" + accesstoken + "]"
if response, err = utils.PostForm(host, url.Values{"image": {sourcestring}}); err != nil {
//logger.Error("user_defined PostForm err", err)
return err
}
var res struct {
ErrorCode int64 `json:"error_code"`
ErrorMsg string `json:"error_msg"`
Conclusion string `json:"conclusion"`
Log_id uint64 `json:"log_id"`
IsHitMd5 bool `json:"isHitMd5"`
ConclusionType int64 `json:"conclusionType"`
}
if err = json.Unmarshal([]byte(response), &res); err != nil {
//err = errors.New(e.GetMsg(e.JsonUnmarshal))
return
}
//logger.Error("user_defined res", res)
if res.ErrorCode != 0 || res.ErrorMsg != "" {
return errors.New(e.GetMsg(e.ERROR_BAIDU_FAIL))
}
if res.Conclusion != "合规" && res.Conclusion != "疑似" {
return errors.New(e.GetMsg(e.ERROR_BAIDU_IMAGE))
}
return nil
}
func PutBos(filePath string, mediaType string, needRemove bool) (url string, err error) {
BOSClient, err := objstorage.NewOSS(config.ConfigData.Oss.AccessKeyId, config.ConfigData.Oss.AccessKeySecret, config.ConfigData.Oss.Endpoint)
if err != nil {
//logger.Errorf("PutBos NewOss err ", err)
err = errors.New(e.GetMsg(e.ErrorUploadBos))
return
}
f, err := os.Open(filePath)
if err != nil {
//logger.Errorf("PutBos Open err %+v", err.Error())
return
}
fileBytes, _ := io.ReadAll(f)
f.Close()
//删除本地文件
if needRemove {
os.Remove(filePath)
}
if mediaType == "image" {
if err = BaiduCheckImage(fileBytes); err != nil {
return
}
}
filePath = strings.Replace(filePath, "./runtime", "", 1)
var objectName string = fmt.Sprintf("%s/%s%s", config.ConfigData.Oss.BaseDir, config.Env, filePath)
_, err = BOSClient.PutObjectFromBytes(config.ConfigData.Oss.BucketName, objectName, fileBytes)
if err != nil {
//logger.Errorf("PutBos PutObject err %+v", err.Error())
err = errors.New(e.GetMsg(e.ErrorUploadBos))
return
}
//url = fmt.Sprintf("%s%s%s/%s", config.BosHttp, config.BosBucketName, config.BosUrl, objectName)
url = fmt.Sprintf("%s/%s", config.ConfigData.Oss.CdnHost, objectName)
return
}
func GetSnapshot(videoPath, snapshotPath string, frameNum int) (snapshotName string, err error) {
buf := bytes.NewBuffer(nil)
zap.L().Info("GetSnapshot", zap.Any("videoPath", videoPath))
err = ffmpeg.Input(videoPath).
Filter("select", ffmpeg.Args{fmt.Sprintf("gte(n,%d)", frameNum)}).
Output("pipe:", ffmpeg.KwArgs{"vframes": 1, "format": "image2", "vcodec": "mjpeg"}).
WithOutput(buf, os.Stdout).
Run()
if err != nil {
zap.L().Error("GetSnapshot Input err", zap.Error(err))
return "", err
}
img, err := imaging.Decode(buf)
if err != nil {
zap.L().Error("GetSnapshot Decode err", zap.Error(err))
return "", err
}
err = imaging.Save(img, snapshotPath+"."+PngType)
if err != nil {
zap.L().Error("GetSnapshot Save err", zap.Error(err))
return "", err
}
names := strings.Split(snapshotPath, "\\")
snapshotName = names[len(names)-1] + "." + PngType
return
}