You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

308 lines
9.3 KiB
Go

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

package common
import (
"bytes"
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"github.com/disintegration/imaging"
"github.com/dubbogo/gost/log/logger"
"github.com/exhibition-main/internal/config"
"github.com/exhibition-main/internal/model"
"github.com/exhibition-main/internal/msg"
"github.com/exhibition-main/internal/response"
"github.com/exhibition-main/pkg/logic"
"github.com/exhibition-main/pkg/utils"
"github.com/fonchain_enterprise/utils/objstorage"
"github.com/gin-gonic/gin"
uuid "github.com/satori/go.uuid"
ffmpeg "github.com/u2takey/ffmpeg-go"
"go.uber.org/zap"
"io/ioutil"
"mime/multipart"
"net/url"
"os"
"path"
"path/filepath"
"strconv"
"strings"
"sync"
)
var (
wg sync.WaitGroup
)
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
source := c.PostForm("source")
mask := c.PostForm("mask")
action := c.PostForm("action")
if mask == "" {
mask = "default"
}
mediaType := c.PostForm("type")
logger.Errorf("UploadImg 1 %+v", 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 {
response.ResponseQuickMsg(c, msg.Fail, errS.Error(), nil)
return
}
}
logger.Errorf("UploadImg 2 %+v", mask)
// 检验参数
if mask == "" || source == "" {
response.ResponseQuickMsg(c, msg.Fail, msg.INVALID_PARAMS, nil)
return
}
file, err := c.FormFile("file")
// 检验文件
if err != nil {
logger.Errorf("Upload FormFile err", err)
response.ResponseQuickMsg(c, msg.Fail, err.Error(), nil)
return
}
logger.Errorf("UploadImg 3 %+v", mask)
// 判断是不是视频或者需要压缩
var oriUrl string
if isCompress != 1 && mediaType != "video" && action == "" {
oriUrl, err = quickBos(file, mediaType, mask, source)
if err != nil {
response.ResponseQuickMsg(c, msg.Fail, err.Error(), nil)
return
}
response.ResponseQuickMsg(c, msg.Ok, msg.SUCCESS, map[string]interface{}{
"ori_url": oriUrl,
})
return
}
logger.Errorf("UploadImg 4 %+v", mask)
//创建文件名
fileExt := strings.ToLower(path.Ext(file.Filename))
filename := uuid.NewV4()
if err != nil {
response.ResponseQuickMsg(c, msg.Fail, err.Error(), nil)
return
}
fileFullName := fmt.Sprintf("%s%s", filename, fileExt)
//检测文件夹 不存在就创建
imgPath := fmt.Sprintf("%s/%s/%s", BasePath, source, mask)
_, err = utils.CheckDirPath(imgPath, true)
if err != nil {
response.ResponseQuickMsg(c, msg.Fail, err.Error(), nil)
return
}
dst := fmt.Sprintf("%s/%s", imgPath, fileFullName)
logger.Errorf("UploadImg 5 %+v", mask)
// 保存文件至指定路径
err = c.SaveUploadedFile(file, dst)
if err != nil {
logger.Errorf("Upload FormFile err", err)
response.ResponseQuickMsg(c, msg.Fail, err.Error(), nil)
return
}
logger.Errorf("UploadImg 6 %+v", mask)
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 = 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 {
logger.Errorf("Upload compress err", err)
response.ResponseQuickMsg(c, msg.Fail, err.Error(), data)
return
}
data["compress_url"] = compressUrl
}
logger.Errorf("UploadImg 7 %+v", mask)
// 如果是视频需要截图图片做封面
if mediaType == VideoType {
videoCover := fmt.Sprintf("%s/%s", imgPath, filename)
_, err = GetSnapshot(dst, videoCover, 1)
if err != nil {
logger.Errorf("GetSnapshot err %+v", err.Error())
response.ResponseQuickMsg(c, msg.Fail, "获取封面失败", err.Error())
return
}
logger.Errorf("UploadImg 8 %+v", mask)
logger.Errorf("UploadImg 8.1 videoCover %+v", 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)
data["cover_url"] = coverUrl
if err != nil {
logger.Errorf("Upload GetSnapshot err", zap.Error(err))
response.ResponseQuickMsg(c, msg.Fail, err.Error(), nil)
return
}
}
ossUrl, err := PutBos(dst, mediaType, true)
if err != nil {
response.ResponseQuickMsg(c, msg.Fail, err.Error(), nil)
return
}
data["ori_url"] = ossUrl
response.ResponseQuickMsg(c, msg.Ok, msg.SUCCESS, data)
return
}
func GetSnapshot(videoPath, snapshotPath string, frameNum int) (snapshotName string, err error) {
buf := bytes.NewBuffer(nil)
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 {
logger.Errorf("GetSnapshot Input err:", zap.Error(err))
return "", err
}
img, err := imaging.Decode(buf)
if err != nil {
logger.Errorf("GetSnapshot Decode err:", zap.Error(err))
return "", err
}
err = imaging.Save(img, snapshotPath+"."+PngType)
if err != nil {
logger.Errorf("GetSnapshot Save err:", zap.Error(err))
return "", err
}
names := strings.Split(snapshotPath, "\\")
snapshotName = names[len(names)-1] + "." + PngType
return
}
func PutBos(filePath string, mediaType string, needRemove bool) (url string, err error) {
BOSClient, err := objstorage.NewOSS(config.Data.Bos.AccessKeyId, config.Data.Bos.AccessKeySecret, config.Data.Bos.Endpoint)
if err != nil {
logger.Errorf("PutBos NewOSS err ", err)
err = errors.New(msg.ErrorUploadBos)
return
}
f, err := os.Open(filePath)
if err != nil {
logger.Errorf("PutBos Open err %+v", err.Error())
return
}
fileBytes, _ := ioutil.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.Data.Bos.BosBaseDir, config.Data.System.Mode, filePath)
_, err = BOSClient.PutObjectFromBytes(config.Data.Bos.BucketName, objectName, fileBytes)
if err != nil {
logger.Errorf("PutBos PutObject err %+v", err.Error())
err = errors.New(msg.ErrorUploadBos)
return
}
url = fmt.Sprintf("%s/%s", config.Data.Bos.CdnHost, objectName)
return
}
func quickBos(file *multipart.FileHeader, mediaType string, mask string, source string) (url string, err error) {
newFile, _ := file.Open()
defer newFile.Close()
uuids := uuid.NewV4()
filePath := fmt.Sprintf("%s/%s/%s/%s%s", mediaType, mask, source, uuids, filepath.Ext(file.Filename))
fileBytes, _ := ioutil.ReadAll(newFile)
if mediaType == "image" {
if err = BaiduCheckImage(fileBytes); err != nil {
return
}
}
var objectName string = fmt.Sprintf("%s/%s/%s", config.Data.Bos.BosBaseDir, config.Data.System.Mode, filePath)
BOSClient, _ := objstorage.NewOSS(config.Data.Bos.AccessKeyId, config.Data.Bos.AccessKeySecret, config.Data.Bos.Endpoint)
_, err = BOSClient.PutObjectFromBytes(config.Data.Bos.BucketName, objectName, fileBytes)
if err != nil {
logger.Errorf("quickBos err", err)
return
}
url = fmt.Sprintf("%s/%s", config.Data.Bos.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(msg.JSON_UNMARSHAL)
return
}
logger.Error("user_defined res", res)
if res.ErrorCode != 0 || res.ErrorMsg != "" {
return errors.New(msg.ERROR_BAIDU_FAIL)
}
if res.Conclusion != "合规" && res.Conclusion != "疑似" {
return errors.New(msg.ERROR_BAIDU_IMAGE)
}
return nil
}