fonchain-fiee/pkg/service/upload/upload.go

322 lines
9.5 KiB
Go
Raw Normal View History

2025-02-22 07:10:20 +00:00
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"
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
}