1556 lines
45 KiB
Go
1556 lines
45 KiB
Go
package vidser
|
|
|
|
import (
|
|
"91porn-server/app/service/taskser"
|
|
"91porn-server/app/service/vidhelpser"
|
|
sli "91porn-server/common/slice"
|
|
"91porn-server/models/v/dailytaskmod"
|
|
"91porn-server/models/v/modulesectionmod"
|
|
"91porn-server/models/v/vidtimeonlinemod"
|
|
"bytes"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"path/filepath"
|
|
"sort"
|
|
"strconv"
|
|
"strings"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/bxcodec/faker/v3/support/slice"
|
|
"go.mongodb.org/mongo-driver/mongo/options"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
|
|
"91porn-server/app/appg"
|
|
"91porn-server/common"
|
|
"91porn-server/common/constant"
|
|
"91porn-server/common/constant/redisconst"
|
|
"91porn-server/common/file"
|
|
"91porn-server/common/httputil"
|
|
"91porn-server/common/log"
|
|
"91porn-server/common/stderr"
|
|
"91porn-server/common/timeutil"
|
|
"91porn-server/models/commod"
|
|
"91porn-server/models/v/imagetopmod"
|
|
"91porn-server/models/v/locmod"
|
|
"91porn-server/models/v/modulevidmod"
|
|
"91porn-server/models/v/operationlogmod"
|
|
"91porn-server/models/v/pushmod"
|
|
"91porn-server/models/v/tagmod"
|
|
"91porn-server/models/v/usermod"
|
|
"91porn-server/models/v/vidmod"
|
|
"91porn-server/web/service/updownloadser"
|
|
"91porn-server/web/vidhelp"
|
|
"91porn-server/web/webg"
|
|
|
|
"github.com/shopspring/decimal"
|
|
"go.mongodb.org/mongo-driver/bson"
|
|
"go.mongodb.org/mongo-driver/bson/primitive"
|
|
)
|
|
|
|
// SubmitBase 提交基本信息
|
|
func SubmitBase(req vidmod.WebSubmitReq) (code stderr.Code, vid primitive.ObjectID) {
|
|
tags := make([]primitive.ObjectID, 0, len(req.Tags))
|
|
for _, t := range req.Tags {
|
|
tid, suc := updownloadser.HandleTag(t, req.Cover)
|
|
if !suc {
|
|
continue
|
|
}
|
|
tags = append(tags, tid)
|
|
}
|
|
l := locmod.Location{
|
|
Longitude: req.Location.Longitude,
|
|
Latitude: req.Location.Latitude,
|
|
Country: req.Location.Country,
|
|
CountryCode: req.Location.CountryCode,
|
|
Province: req.Location.Province,
|
|
ProvinceCode: req.Location.ProvinceCode,
|
|
City: req.Location.City,
|
|
CityCode: req.Location.CityCode,
|
|
Address: req.Location.Address,
|
|
Visit: 0,
|
|
}
|
|
if err := locmod.InsertLocationInfo(l); err != nil {
|
|
return stderr.ErrDbInsertError, primitive.NilObjectID
|
|
}
|
|
lid, err := locmod.GetLocationIDByCity(req.Location.City)
|
|
if err != nil {
|
|
return stderr.ErrDbQueryError, primitive.NilObjectID
|
|
}
|
|
series := []string{}
|
|
if len(req.SeriesCover) != 0 {
|
|
series = req.SeriesCover
|
|
}
|
|
oid, _ := primitive.ObjectIDFromHex(req.SourceID)
|
|
v := vidmod.VideoModel{
|
|
ID: oid,
|
|
NewsType: req.NewsType,
|
|
PublisherID: req.UID,
|
|
Title: req.Title,
|
|
Content: req.Content,
|
|
MimeType: req.MimeType,
|
|
Tags: tags,
|
|
SourceID: req.SourceID,
|
|
SourceURL: req.SourceURL,
|
|
PlayTime: req.PlayTime,
|
|
Cover: req.Cover,
|
|
CoverThumb: req.CoverThumb,
|
|
Activity: []primitive.ObjectID{},
|
|
SeriesCover: series,
|
|
SeriesNum: len(series),
|
|
Via: req.Via,
|
|
Size: req.Size,
|
|
Rating: 0,
|
|
PlayCount: 0,
|
|
Coins: req.Coins,
|
|
LikeCount: 0,
|
|
CommentCount: 0,
|
|
ShareCount: 0,
|
|
Status: 0,
|
|
Location: lid,
|
|
FreeTime: req.FreeTime,
|
|
CreatedAt: time.Now(),
|
|
UpdatedAt: time.Now(),
|
|
Width: req.Width,
|
|
Height: req.Height,
|
|
MDSID: req.MDSID,
|
|
VerticalCover: req.VerticalCover,
|
|
Ratio: req.Ratio,
|
|
Resolution: req.Resolution,
|
|
SeedLinkUrl: req.SeedLinkUrl,
|
|
SeedSize: req.SeedSize,
|
|
SeedPlayTime: req.SeedPlayTime,
|
|
RichText: req.RichText,
|
|
PreviewStart: req.PreviewStart,
|
|
}
|
|
if len(v.Tags) > 0 && req.Status == 1 {
|
|
v.Status = req.Status
|
|
v.ReviewAt = time.Now()
|
|
v.ReviewAccount = req.Account
|
|
} else if req.Status == vidmod.OnlinePass {
|
|
v.Status = req.Status
|
|
}
|
|
if vid, err = vidmod.InsertBase(v); err != nil {
|
|
return stderr.ErrDbInsertError, primitive.NilObjectID
|
|
}
|
|
for _, t := range tags {
|
|
if err = tagmod.IncreaseTagVidCount(t, 1); err != nil {
|
|
log.Error("SubmitBase error", log.Any("req", req), log.E(err))
|
|
continue
|
|
}
|
|
}
|
|
return stderr.Success, vid
|
|
}
|
|
|
|
// SendBaseInfo2AWs 上传基本文件信息到aws
|
|
func SendBaseInfo2AWs(req vidmod.WebSubmitReq) (code stderr.Code) {
|
|
info := vidmod.BaseVid4Aws{
|
|
ID: req.SourceID,
|
|
Tags: req.Tags,
|
|
CheckSum: req.MD5,
|
|
Title: req.Title,
|
|
Actors: []string{req.Actor},
|
|
AddedTime: time.Now().Format("2006-01-02"),
|
|
PlayTime: uint64(req.PlayTime),
|
|
Size: req.Size,
|
|
Filename: req.Filename,
|
|
Via: "q1",
|
|
Type: "sp",
|
|
}
|
|
params, _ := common.ToJsonM(info)
|
|
respBody := commod.Resp{}
|
|
if _, err := httputil.DefaultClientPostJsonWithResp(&respBody, webg.Conf.URL.FileInfoUrl, nil, params); err != nil {
|
|
log.Error("SendBaseInfo2AWs error", log.Any("req", req), log.E(err))
|
|
return stderr.Failure
|
|
}
|
|
if respBody.Code != stderr.Success {
|
|
log.Error("SendBaseInfo2AWs status error", log.Any("req", req), log.Any("respBody.Code", respBody.Code))
|
|
return stderr.Failure
|
|
}
|
|
return stderr.Success
|
|
}
|
|
|
|
// MAP 别名
|
|
type MAP map[string]interface{}
|
|
|
|
func ExportVidList(cond MAP, modeList SortModeList) (buff bytes.Buffer, code stderr.Code) {
|
|
var err error
|
|
var secID primitive.ObjectID
|
|
secID, cond, _, err = dealVidListCond(cond)
|
|
if code = err.(stderr.Code); code != stderr.Success {
|
|
return
|
|
}
|
|
sort := make(primitive.D, len(modeList))
|
|
for i, v := range modeList {
|
|
sort[i] = bson.E{Key: v.Field, Value: v.Value}
|
|
}
|
|
step := 900
|
|
page := 1
|
|
vModels, total, err := vidmod.GetvideoListByMapCond(cond, sort, uint64(page), uint64(step))
|
|
if err != nil {
|
|
code = stderr.ErrDbQueryError
|
|
return
|
|
}
|
|
if total > 30000 {
|
|
code = stderr.ErrDbTooMuchRecords
|
|
return
|
|
}
|
|
allVideoInfos, err := vidhelp.EncodeVideoInfo(vModels, secID)
|
|
if err != nil {
|
|
code = stderr.ErrDbQueryError
|
|
return
|
|
}
|
|
wg := sync.WaitGroup{}
|
|
totalPages := int(total)/step + 1
|
|
out := make(chan []*vidmod.WebVideo, totalPages)
|
|
for page++; page <= totalPages; page++ {
|
|
wg.Add(1)
|
|
common.GoParam(page, func(i int) {
|
|
defer wg.Done()
|
|
vModels, _, err = vidmod.GetvideoListByMapCond(cond, sort, uint64(i), uint64(step))
|
|
if err != nil {
|
|
log.Error("vidmod.GetvideoListByMapCond", log.Any("cond", cond), log.Any("sort", sort),
|
|
log.Any("page", page), log.Any("step", step), log.E(err))
|
|
return
|
|
}
|
|
infos, err := vidhelp.EncodeVideoInfo(vModels, secID)
|
|
if err != nil {
|
|
return
|
|
}
|
|
out <- infos
|
|
})
|
|
}
|
|
common.Go(func() {
|
|
wg.Wait()
|
|
close(out)
|
|
})
|
|
for vs := range out {
|
|
allVideoInfos = append(allVideoInfos, vs...)
|
|
}
|
|
excelFile := file.WriteStruct2Xlsx("帖子列表", allVideoInfos)
|
|
defer excelFile.Close()
|
|
_ = excelFile.DeleteSheet("Sheet1")
|
|
_, _ = excelFile.WriteTo(&buff)
|
|
return
|
|
}
|
|
|
|
// GetVidList 获取视频列表
|
|
func GetVidList(cond MAP, modeList SortModeList, page, size uint64, isPush bool) (code stderr.Code, data vidmod.ListResp) {
|
|
// 为了不影响查询结果,点赞率与成交率优先处理
|
|
var purchaseRate, likeRate int
|
|
if item, ok := cond["purchaseRate"]; ok {
|
|
// 防止panic,断言未命中默认为类型默认值
|
|
purchaseRate, _ = item.(int)
|
|
delete(cond, "purchaseRate")
|
|
}
|
|
if item, ok := cond["likeRate"]; ok {
|
|
likeRate, _ = item.(int)
|
|
delete(cond, "likeRate")
|
|
}
|
|
secID, cond, videoIDs, err := dealVidListCond(cond)
|
|
if code = err.(stderr.Code); code != stderr.Success {
|
|
return
|
|
}
|
|
s := make(primitive.D, len(modeList))
|
|
for i, v := range modeList {
|
|
s[i] = bson.E{Key: v.Field, Value: v.Value}
|
|
}
|
|
//是否强推
|
|
if isPush {
|
|
//查询强推视频
|
|
pushList, _, _, err := pushmod.GetPushList(page, size, bson.M{}, bson.D{{Key: "createdAt", Value: -1}})
|
|
if err != nil {
|
|
return stderr.ErrDbQueryError, data
|
|
}
|
|
if len(pushList) <= 0 {
|
|
return stderr.Success, data
|
|
}
|
|
vidIds := make([]primitive.ObjectID, len(pushList))
|
|
for i, p := range pushList {
|
|
vidIds[i] = p.VideoID
|
|
}
|
|
cond["_id"] = bson.M{"$in": vidIds}
|
|
}
|
|
log.Info("---", log.Any("cond", cond), log.Any("sort", s))
|
|
// 这里会打乱之前排序
|
|
vModels, total, err := vidmod.GetvideoListByMapCond(cond, s, page, size)
|
|
if err != nil {
|
|
return stderr.ErrDbQueryError, data
|
|
}
|
|
// 因为查询数据库后数据会打乱,因此此处重新根据专题序号进行排序
|
|
if !secID.IsZero() {
|
|
newVideos := make([]*vidmod.VideoModel, 0, len(videoIDs))
|
|
for _, v := range videoIDs {
|
|
for _, vv := range vModels {
|
|
if v == vv.ID {
|
|
newVideos = append(newVideos, vv)
|
|
break
|
|
}
|
|
}
|
|
}
|
|
vModels = newVideos
|
|
}
|
|
infos, err := vidhelp.EncodeVideoInfo(vModels, secID)
|
|
if err != nil {
|
|
return stderr.ErrDbQueryError, data
|
|
}
|
|
// 当前搜索结果按照成交率排序,正序
|
|
if purchaseRate == 1 {
|
|
sort.Slice(infos, func(i, j int) bool {
|
|
return infos[i].PurchaseRate < infos[j].PurchaseRate
|
|
})
|
|
}
|
|
// 倒序
|
|
if purchaseRate == -1 {
|
|
sort.Slice(infos, func(i, j int) bool {
|
|
return infos[i].PurchaseRate > infos[j].PurchaseRate
|
|
})
|
|
}
|
|
// 当前搜索结果按照点击率排序,正序
|
|
if likeRate == 1 {
|
|
sort.Slice(infos, func(i, j int) bool {
|
|
return infos[i].LikeRate < infos[j].LikeRate
|
|
})
|
|
}
|
|
// 倒序
|
|
if likeRate == -1 {
|
|
sort.Slice(infos, func(i, j int) bool {
|
|
return infos[i].LikeRate > infos[j].LikeRate
|
|
})
|
|
}
|
|
return stderr.Success, vidmod.ListResp{VInfos: infos, Total: total}
|
|
}
|
|
|
|
func dealVidListCond(cond MAP) (primitive.ObjectID, MAP, []primitive.ObjectID, error) {
|
|
var secID primitive.ObjectID
|
|
var err error
|
|
sectionID, ok := cond["sectionID"]
|
|
if ok {
|
|
secID, err = primitive.ObjectIDFromHex(sectionID.(string))
|
|
if err != nil {
|
|
log.Error("primitive.ObjectIDFromHex", log.Any("sectionID", sectionID), log.E(err))
|
|
return secID, cond, nil, stderr.ErrDbQueryError
|
|
}
|
|
var flag bool
|
|
isSorted, ok := cond["isSortedUnderModule"]
|
|
if ok {
|
|
flag = isSorted.(bool)
|
|
}
|
|
videoIDs, err := modulevidmod.GetBySectionID(secID, flag)
|
|
if err != nil {
|
|
return secID, cond, nil, stderr.ErrDbQueryError
|
|
}
|
|
cond["_id"] = bson.M{"$in": videoIDs}
|
|
delete(cond, "sectionID")
|
|
delete(cond, "isSortedUnderModule")
|
|
return secID, cond, videoIDs, stderr.Success
|
|
}
|
|
delete(cond, "sectionID")
|
|
delete(cond, "isSortedUnderModule")
|
|
return secID, cond, nil, stderr.Success
|
|
}
|
|
|
|
func updateTagVideoCnt(oldTags, newTags []primitive.ObjectID) {
|
|
mOld := make(map[primitive.ObjectID]bool)
|
|
mNew := make(map[primitive.ObjectID]bool)
|
|
for _, v := range newTags {
|
|
mNew[v] = true
|
|
}
|
|
for _, v := range oldTags {
|
|
mOld[v] = true
|
|
}
|
|
for _, v := range newTags {
|
|
if !mOld[v] {
|
|
_ = tagmod.IncreaseTagVidCount(v, 1)
|
|
}
|
|
}
|
|
for _, v := range oldTags {
|
|
if !mNew[v] {
|
|
_ = tagmod.IncreaseTagVidCount(v, -1)
|
|
}
|
|
}
|
|
}
|
|
|
|
func updatePublisherRewarded(id string, specReward int) {
|
|
info, err := vidmod.GetVideoInfo(id)
|
|
if err != nil {
|
|
return
|
|
}
|
|
_ = usermod.IncRewarded(info.PublisherID, decimal.NewFromInt(int64(specReward)))
|
|
}
|
|
|
|
// UpdateVidInfo 更新视频信息
|
|
func UpdateVidInfo(req vidmod.EditReq, manager string) (code stderr.Code, data interface{}) {
|
|
vidInfo, err := vidmod.GetVideoInfo(req.ID)
|
|
if err != nil {
|
|
log.Error("UpdateVidInfo error", log.Any("req", req), log.E(err))
|
|
return stderr.CommentVideoInfoErr, nil
|
|
}
|
|
|
|
// —— 上架相关时做敏感词校验 ——
|
|
// 触发条件:
|
|
// 1. status 切换到 上架(CheckPass=1) / 上架并免费(Free=3)
|
|
// 2. 当前已上架(1/3) 且本次更新涉及 Title/Content/RichText
|
|
// 校验文本: req 提供则用新值, 否则用 DB 现值(即"落库后"的文本快照)
|
|
if shouldCheckSensitiveOnUpdate(vidInfo, req) {
|
|
title := vidInfo.Title
|
|
content := vidInfo.Content
|
|
richText := vidInfo.RichText
|
|
if req.Title != nil {
|
|
title = *req.Title
|
|
}
|
|
if req.Content != nil {
|
|
content = *req.Content
|
|
}
|
|
if req.RichText != nil {
|
|
richText = *req.RichText
|
|
}
|
|
if err := CheckShelvingFields(vidInfo.ID, title, content, richText); err != nil {
|
|
return stderr.ContentSensitiveHit, err.Error()
|
|
}
|
|
}
|
|
|
|
if req.Type == 2 {
|
|
if !vidInfo.ID.IsZero() && req.RichText != nil {
|
|
if _, err = vidmod.UpdateVideoByMapCond(vidInfo.ID, bson.M{"richText": req.RichText}); err != nil {
|
|
return stderr.ErrDbUpdateError, nil
|
|
}
|
|
return stderr.Success, nil
|
|
}
|
|
return stderr.ErrParamError, nil
|
|
}
|
|
|
|
if req.Status != nil && *req.Status != vidInfo.Status {
|
|
if err = operationlogmod.Insert(operationlogmod.OperationLog{
|
|
ID: primitive.NewObjectID(),
|
|
OperationType: constant.Media_Edit_Status,
|
|
BeforeContent: fmt.Sprintf("%v", vidInfo.Status),
|
|
AfterContent: fmt.Sprintf("%v", *req.Status),
|
|
CreatedUser: manager,
|
|
}); err != nil {
|
|
return stderr.ErrDbInsertError, nil
|
|
}
|
|
}
|
|
if req.Coins != nil && int64(*req.Coins) != vidInfo.Coins {
|
|
if err = operationlogmod.Insert(operationlogmod.OperationLog{
|
|
ID: primitive.NewObjectID(),
|
|
OperationType: constant.Media_Edit_Price,
|
|
BeforeContent: fmt.Sprintf("%v", vidInfo.Coins),
|
|
AfterContent: fmt.Sprintf("%v", *req.Coins),
|
|
CreatedUser: manager,
|
|
}); err != nil {
|
|
return stderr.ErrDbInsertError, nil
|
|
}
|
|
}
|
|
if req.Title != nil && *req.Title != vidInfo.Title {
|
|
if err = operationlogmod.Insert(operationlogmod.OperationLog{
|
|
ID: primitive.NewObjectID(),
|
|
OperationType: constant.Media_Edit_Content,
|
|
BeforeContent: fmt.Sprintf("%v", vidInfo.Title),
|
|
AfterContent: fmt.Sprintf("%v", *req.Title),
|
|
CreatedUser: manager,
|
|
}); err != nil {
|
|
return stderr.ErrDbInsertError, nil
|
|
}
|
|
}
|
|
oid, err := primitive.ObjectIDFromHex(req.ID)
|
|
if err != nil {
|
|
log.Error("UpdateVidInfo error", log.Any("req", req), log.E(err))
|
|
return stderr.ErrParamError, nil
|
|
}
|
|
if req.FakeLikeCount != nil {
|
|
gt, err := vidmod.FakeLikeGteLike(req.ID, *req.FakeLikeCount)
|
|
if err != nil {
|
|
return stderr.ErrDbQueryError, nil
|
|
}
|
|
if !gt {
|
|
return stderr.ErrParamError, "fakelikecount need gte likecount."
|
|
}
|
|
}
|
|
oldTags, err := vidmod.GetVideoTag(req.ID)
|
|
if err != nil {
|
|
return stderr.ErrDbQueryError, nil
|
|
}
|
|
set := bson.M{}
|
|
if req.SeriesCover != nil {
|
|
sn := len(*req.SeriesCover)
|
|
req.SeriesNum = &sn
|
|
}
|
|
videoInfo, err := vidmod.GetVideoInfo(req.ID)
|
|
if err != nil {
|
|
return
|
|
}
|
|
if req.WorksSort != nil {
|
|
if *req.WorksSort != 0 && videoInfo.WorksSort != *req.WorksSort {
|
|
// 查询并修改重复排序
|
|
err = vidmod.UpdateWorksSort(videoInfo.PublisherID, videoInfo.WorksSort, *req.WorksSort)
|
|
if err != nil {
|
|
return
|
|
}
|
|
}
|
|
}
|
|
if req.Type == 0 {
|
|
set, _ = common.ToBsonM(req.EditInfo)
|
|
}
|
|
newTags := []primitive.ObjectID{}
|
|
if len(req.Tags) > 0 {
|
|
newTags = vidhelp.AddTags(req.ID, req.Tags)
|
|
set["tags"] = newTags
|
|
}
|
|
if len(req.TagSort) > 0 {
|
|
set["tagSort"] = covertTagSort(req)
|
|
}
|
|
if req.CreatedAt != nil && len(*req.CreatedAt) != 0 {
|
|
createdAt := timeutil.StrTimeToTime(*req.CreatedAt)
|
|
set["createdAt"] = createdAt
|
|
}
|
|
if req.Status != nil && *req.Status == vidmod.CheckPass && *req.Status != vidInfo.Status {
|
|
set["reviewAt"] = time.Now()
|
|
}
|
|
if req.PublisherID != nil {
|
|
set["publisherID"] = req.PublisherID
|
|
}
|
|
if req.Content != nil {
|
|
set["content"] = req.Content
|
|
}
|
|
if req.PreviewURL != nil {
|
|
set["previewURL"] = *req.PreviewURL
|
|
}
|
|
if req.UpTag != nil {
|
|
set["upTag"] = *req.UpTag
|
|
}
|
|
if req.NewsType != nil {
|
|
set["newsType"] = req.NewsType
|
|
}
|
|
if req.TimeNodeList != nil {
|
|
set["timeNodeList"] = *req.TimeNodeList
|
|
}
|
|
//if req.LiaoBaTop != nil {
|
|
// set["liaoBaTop"] = *req.LiaoBaTop
|
|
//}
|
|
applyLiaoBaTopSort(set, req.LiaoBaTopSort)
|
|
if req.ActivityID != nil {
|
|
if *req.ActivityID == "" {
|
|
set["activityId"] = primitive.NilObjectID
|
|
} else {
|
|
activityId, err := primitive.ObjectIDFromHex(*req.ActivityID)
|
|
if err != nil {
|
|
log.Error(fmt.Sprintf("解析参赛作品活动ID异常:%v", err), log.Any("activityID:", *req.ActivityID))
|
|
return stderr.ErrParamError, nil
|
|
}
|
|
set["activityId"] = activityId
|
|
}
|
|
}
|
|
if req.HappinessPlazaTop != nil {
|
|
set["happinessPlazaTop"] = req.HappinessPlazaTop
|
|
id, _ := primitive.ObjectIDFromHex(req.ID)
|
|
if *req.HappinessPlazaTop == 1 {
|
|
//插入幸福广场置顶
|
|
imgTop := imagetopmod.ImageTopModel{
|
|
ID: primitive.NilObjectID,
|
|
NewSort: 0,
|
|
NewEndTime: &time.Time{},
|
|
RecommendSort: 0,
|
|
RecommendEndTime: &time.Time{},
|
|
UpdatedAt: time.Now(),
|
|
}
|
|
imgTop.ImageId = id
|
|
//插入数据
|
|
if err = imagetopmod.InsertOne(&imgTop); err != nil {
|
|
return stderr.ErrDbInsertError, nil
|
|
}
|
|
} else {
|
|
//删除幸福广场置顶
|
|
if err = imagetopmod.DeleteOne(id); err != nil {
|
|
return stderr.ErrDbDeleteError, nil
|
|
}
|
|
}
|
|
}
|
|
if req.ShareSort != nil {
|
|
set["shareSort"] = *req.ShareSort
|
|
}
|
|
delete(set, "fakeRewarded")
|
|
if _, err = vidmod.UpdateVideoByMapCond(oid, set); err != nil {
|
|
return stderr.ErrDbUpdateError, nil
|
|
}
|
|
if req.NewsType != nil {
|
|
// 更新
|
|
modulevidmod.UpdateNewsTypeByVideoID(oid, *req.NewsType)
|
|
}
|
|
updateTagVideoCnt(oldTags, newTags)
|
|
if req.FakeRewarded != nil {
|
|
updatePublisherRewarded(req.ID, *req.FakeRewarded)
|
|
_ = vidmod.IncSpecFakeRewarded(oid, decimal.NewFromInt(int64(*req.FakeRewarded)))
|
|
}
|
|
format := redisconst.VideoInfoKey()
|
|
s := fmt.Sprintf(format, videoInfo.ID.Hex())
|
|
if _, err = webg.Redis.Del(s); err != nil {
|
|
return stderr.ErrDbUpdateError, nil
|
|
}
|
|
return stderr.Success, nil
|
|
}
|
|
|
|
// applyLiaoBaTopSort only builds the update for the video currently being
|
|
// edited. Duplicate sort values are intentional and must not mutate another
|
|
// video that already uses the same value.
|
|
func applyLiaoBaTopSort(set bson.M, sortCode *int) {
|
|
if sortCode == nil {
|
|
return
|
|
}
|
|
set["liaoBaTop"] = *sortCode > 0
|
|
set["liaoBaTopSort"] = *sortCode
|
|
}
|
|
|
|
func covertTagSort(info vidmod.EditReq) bson.M {
|
|
set := make(bson.M, 10)
|
|
for _, v := range info.TagSort {
|
|
set[v.TagId] = v.SortCode
|
|
}
|
|
return set
|
|
}
|
|
|
|
// DeleteManyByTTL 删除视频 被删除的视屏归属为officialUID,未审核或审核未通过的视屏通过TTL删除
|
|
func DeleteManyByTTL(ids ...primitive.ObjectID) (code stderr.Code, data interface{}) {
|
|
delSetDoc := (&vidmod.SetDoc{}).SetPublisherID(constant.DeleteUID).SetDeleteAt(time.Now()).SetStatus(vidmod.CheckFailure)
|
|
if _, err := vidmod.ModifyMany(ids, *delSetDoc); err != nil {
|
|
return stderr.ErrDbUpdateError, nil
|
|
}
|
|
if err := modulevidmod.DeleteManyByVids(ids); err != nil {
|
|
return stderr.ErrDbDeleteError, nil
|
|
}
|
|
return stderr.Success, nil
|
|
}
|
|
|
|
func BatchUpdateReco(req vidmod.BatchUpdateRecoRequest) error {
|
|
return vidmod.BatchUpdateReco(req.IDs, req.Reco)
|
|
}
|
|
|
|
// UpdateVids 批量更新视频信息
|
|
func UpdateVids(req vidmod.EditManyReq) (code stderr.Code, data interface{}) {
|
|
if len(req.IDs) == 0 {
|
|
return
|
|
}
|
|
oids := make([]primitive.ObjectID, 0, len(req.IDs))
|
|
for _, id := range req.IDs {
|
|
oid, err := primitive.ObjectIDFromHex(id)
|
|
if err != nil {
|
|
log.Error("UpdateVids error", log.Any("req", req), log.E(err))
|
|
continue
|
|
}
|
|
oids = append(oids, oid)
|
|
}
|
|
// 上架(UpStatus=1 上架 / 3 上架并免费)前置敏感词校验
|
|
if req.UpStatus != nil && (*req.UpStatus == vidmod.CheckPass || *req.UpStatus == vidmod.Free) {
|
|
if err := CheckShelvingByIDs(oids); err != nil {
|
|
return stderr.ContentSensitiveHit, err.Error()
|
|
}
|
|
}
|
|
newTags := vidhelp.AddTags(req.IDs[0], req.Tags)
|
|
req.TagIds = append(req.TagIds, newTags...)
|
|
req.TagIds = common.Deduplication(req.TagIds)
|
|
var (
|
|
count int64
|
|
err error
|
|
)
|
|
|
|
if req.Field != "" { // 只更新某个状态
|
|
count, err = vidmod.UpdateVideoBatch(oids, req.Field, req.Status)
|
|
if err != nil {
|
|
if err.Error() == "overLiaoBaLimit" {
|
|
return stderr.LiaoBaTopOverLimit, nil
|
|
}
|
|
return stderr.ErrDbUpdateError, nil
|
|
}
|
|
} else if req.OriginPublisherID != nil && req.PublisherID != nil {
|
|
filter := bson.M{"publisherID": *req.OriginPublisherID}
|
|
updateData := bson.M{
|
|
"$set": bson.M{"publisherID": *req.PublisherID},
|
|
}
|
|
// 进行视频转移
|
|
err = vidmod.UpdateMany(filter, updateData)
|
|
if err != nil {
|
|
log.Error("帖子批量转移失败",
|
|
log.Any("OriginPublisherID", *req.OriginPublisherID),
|
|
log.Any("PublisherID", *req.PublisherID),
|
|
log.E(err),
|
|
)
|
|
return stderr.ErrDbUpdateError, nil
|
|
}
|
|
} else {
|
|
// 更新tag或者价格
|
|
var updater = bson.M{
|
|
"updatedAt": time.Now(),
|
|
}
|
|
if req.Coins != nil {
|
|
updater["coins"] = req.Coins
|
|
}
|
|
if req.PublisherID != nil {
|
|
updater["publisherID"] = req.PublisherID
|
|
}
|
|
if req.UpStatus != nil {
|
|
updater["status"] = *req.UpStatus
|
|
}
|
|
if req.FreeTime != nil {
|
|
updater["freeTime"] = *req.FreeTime
|
|
}
|
|
if req.DownloadAllow != nil {
|
|
updater["downloadAllow"] = *req.DownloadAllow
|
|
}
|
|
// 这里不去判断tag存不存在,因为tag列表是从服务器拉下去的数据,选中上来的tag也是在数据中存在的
|
|
if len(req.TagIds) > 0 {
|
|
updater["tags"] = req.TagIds
|
|
// 获取相关视频
|
|
videoList, err := vidmod.GetVideoListByIDsNoStatus(oids)
|
|
if err != nil {
|
|
log.Error(fmt.Sprintf("UpdateVidTags vidmod.GetVideoListByIDsNoStatus err:%v, ids:%v", err, req.IDs))
|
|
return stderr.ErrDbQueryError, nil
|
|
}
|
|
var tagMap = map[primitive.ObjectID]int{}
|
|
for _, v := range videoList {
|
|
for _, v := range v.Tags {
|
|
tagMap[v] = tagMap[v] - 1
|
|
}
|
|
}
|
|
for _, tid := range req.TagIds {
|
|
tagMap[tid] = len(videoList)
|
|
}
|
|
// 修改旧tag与新tag的视频数量
|
|
tagmod.IncTagVidCountByMap(tagMap)
|
|
}
|
|
count, err = vidmod.UpdateManyVideo(oids, updater)
|
|
if err != nil {
|
|
log.Error(fmt.Sprintf("UpdateVids vidmod.UpdateManyVideo err:%v, ids:%v", err, req.IDs))
|
|
return stderr.ErrDbQueryError, nil
|
|
}
|
|
}
|
|
|
|
return stderr.Success, vidmod.OperateResult{Count: count}
|
|
}
|
|
|
|
// PassAndEditVids 批量审核更新更新视频信息
|
|
func PassAndEditVids(req vidmod.PassManyReq, manager string) (code stderr.Code, data interface{}) {
|
|
// 上架(含直接通过 / 通过并免费)前置敏感词校验
|
|
if req.Pass == vidmod.CheckPass || req.Pass == vidmod.Free {
|
|
ids := make([]string, 0, len(req.Infos))
|
|
for _, info := range req.Infos {
|
|
ids = append(ids, info.ID)
|
|
}
|
|
if err := CheckShelvingByIDs(parseObjectIDs(ids)); err != nil {
|
|
return stderr.ContentSensitiveHit, err.Error()
|
|
}
|
|
}
|
|
var cnt int64 = 0
|
|
var mergingCnt, convertingCnt, mergeErrorCnt, convertErrorCnt int64
|
|
for _, info := range req.Infos {
|
|
oid, err := primitive.ObjectIDFromHex(info.ID)
|
|
if err != nil {
|
|
log.Error("UpdateVids error", log.Any("req", req), log.E(err))
|
|
continue
|
|
}
|
|
//非图集才需要同步
|
|
isCover, err := vidmod.IsNewsCover(info.ID)
|
|
if err != nil {
|
|
return stderr.ErrDbQueryError, nil
|
|
}
|
|
if req.Pass == 3 || req.Pass == 1 {
|
|
if !isCover {
|
|
if code := SyncFileFromFs(info.ID); code != stderr.UpLoadFileComplete {
|
|
switch code {
|
|
case stderr.FileMerging:
|
|
mergingCnt++
|
|
case stderr.FileConverting:
|
|
convertingCnt++
|
|
case stderr.ErrMergeFile:
|
|
mergeErrorCnt++
|
|
case stderr.ErrConvertFile:
|
|
convertErrorCnt++
|
|
}
|
|
continue
|
|
}
|
|
}
|
|
}
|
|
if req.Pass == 2 {
|
|
if !isCover {
|
|
_ = SyncFileFromFsForNoPassed(info.ID)
|
|
}
|
|
}
|
|
set := make(bson.M)
|
|
set["status"] = req.Pass
|
|
set["coins"] = info.Coins
|
|
if req.Pass == vidmod.Free {
|
|
set["status"] = vidmod.CheckPass
|
|
set["coins"] = 0
|
|
}
|
|
now := time.Now()
|
|
set["reason"] = info.Reason
|
|
set["freeTime"] = info.FreeTime
|
|
set["updatedAt"] = now
|
|
set["reviewAt"] = now
|
|
set["reviewAccount"] = manager
|
|
// 查询视频信息
|
|
videoInfo, err := vidmod.GetVideoInfo(oid.Hex())
|
|
if err != nil {
|
|
return stderr.ErrDbQueryError, nil
|
|
}
|
|
if err = operationlogmod.Insert(operationlogmod.OperationLog{
|
|
ID: primitive.NewObjectID(),
|
|
OperationType: constant.Media_Edit_Status,
|
|
BeforeContent: fmt.Sprintf("%v", videoInfo.Status),
|
|
AfterContent: fmt.Sprintf("%v", req.Pass),
|
|
CreatedUser: manager,
|
|
}); err != nil {
|
|
return stderr.ErrDbInsertError, nil
|
|
}
|
|
if err = operationlogmod.Insert(operationlogmod.OperationLog{
|
|
ID: primitive.NewObjectID(),
|
|
OperationType: constant.Media_Edit_Remark,
|
|
BeforeContent: fmt.Sprintf("%v", ""),
|
|
AfterContent: fmt.Sprintf("%v", info.Reason),
|
|
CreatedUser: manager,
|
|
}); err != nil {
|
|
return stderr.ErrDbInsertError, nil
|
|
}
|
|
if set["status"] == vidmod.CheckPass {
|
|
tagSort := make(bson.M, len(videoInfo.Tags))
|
|
for _, v := range videoInfo.Tags {
|
|
tagSort[v.Hex()] = 0
|
|
}
|
|
set["tagSort"] = tagSort
|
|
}
|
|
_, err = vidmod.UpdateVideoByMapCond(oid, set)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
cnt++
|
|
}
|
|
or := vidmod.OperateResult{Count: cnt, MergingCnt: mergingCnt, ConvertingCnt: convertingCnt, MerErrCnt: mergeErrorCnt, ConvertErrCnt: convertErrorCnt}
|
|
return stderr.Success, or
|
|
}
|
|
|
|
// PassVid 通过审核
|
|
func PassVid(req vidmod.BatchReq, manager string) (code stderr.Code, data interface{}) {
|
|
var mergingCnt, convertingCnt, mergeErrorCnt, convertErrorCnt int64
|
|
if req.Pass != 1 && req.Pass != 2 && req.Pass != 3 {
|
|
log.Error("PassVid error", log.Any("req", req))
|
|
return stderr.ErrParamError, nil
|
|
}
|
|
// 上架(含直接通过 / 通过并免费)前置敏感词校验
|
|
if req.Pass == vidmod.CheckPass || req.Pass == vidmod.Free {
|
|
if err := CheckShelvingByIDs(parseObjectIDs(req.IDs)); err != nil {
|
|
return stderr.ContentSensitiveHit, err.Error()
|
|
}
|
|
}
|
|
oids := make([]primitive.ObjectID, 0, len(req.IDs))
|
|
for _, id := range req.IDs {
|
|
oid, err := primitive.ObjectIDFromHex(id)
|
|
if err != nil {
|
|
log.Error("PassVid2 error", log.Any("req", req), log.E(err))
|
|
continue
|
|
}
|
|
//非图集才需要同步
|
|
info, err := vidmod.GetVideoInfo(id)
|
|
if err != nil {
|
|
return stderr.ErrDbQueryError, nil
|
|
}
|
|
if req.Pass == 3 || req.Pass == 1 {
|
|
if !info.IsCover() {
|
|
if code = SyncFileFromFs(id); code != stderr.UpLoadFileComplete {
|
|
switch code {
|
|
case stderr.FileMerging:
|
|
mergingCnt++
|
|
case stderr.FileConverting:
|
|
convertingCnt++
|
|
case stderr.ErrMergeFile:
|
|
mergeErrorCnt++
|
|
case stderr.ErrConvertFile:
|
|
convertErrorCnt++
|
|
}
|
|
log.Info(fmt.Sprintf("check vid pass code[%v]", code))
|
|
continue
|
|
}
|
|
}
|
|
}
|
|
if req.Pass == 2 {
|
|
if !info.IsCover() {
|
|
_ = SyncFileFromFsForNoPassed(id)
|
|
}
|
|
}
|
|
//此行代码 明白意思 再移动顺序,没有明白则,不要随便移动
|
|
oids = append(oids, oid)
|
|
|
|
tagSort := make(bson.M, len(info.Tags))
|
|
for _, v := range info.Tags {
|
|
tagSort[v.Hex()] = 0
|
|
}
|
|
_, err = vidmod.PassVids(oid, req.Pass, req.Reason, manager, tagSort)
|
|
if err != nil {
|
|
return stderr.ErrDbUpdateError, nil
|
|
}
|
|
// 完成发布任务
|
|
_ = taskser.CompleteDailyTask(nil, info.PublisherID, dailytaskmod.DailyPublish)
|
|
}
|
|
if len(oids) > 0 {
|
|
err := operationlogmod.Insert(operationlogmod.OperationLog{
|
|
ID: primitive.NewObjectID(),
|
|
OperationType: constant.Media_Edit_Status,
|
|
//BeforeContent: fmt.Sprintf("%v", videoInfo.Status),
|
|
AfterContent: fmt.Sprintf("%v", req.Pass),
|
|
CreatedUser: manager,
|
|
})
|
|
if err != nil {
|
|
return stderr.ErrDbInsertError, nil
|
|
}
|
|
err = operationlogmod.Insert(operationlogmod.OperationLog{
|
|
ID: primitive.NewObjectID(),
|
|
OperationType: constant.Media_Edit_Remark,
|
|
BeforeContent: fmt.Sprintf("%v", ""),
|
|
AfterContent: fmt.Sprintf("%v", req.Reason),
|
|
CreatedUser: manager,
|
|
})
|
|
if err != nil {
|
|
return stderr.ErrDbInsertError, nil
|
|
}
|
|
}
|
|
or := vidmod.OperateResult{Count: 1, MergingCnt: mergingCnt, ConvertingCnt: convertingCnt, MerErrCnt: mergeErrorCnt, ConvertErrCnt: convertErrorCnt}
|
|
return stderr.Success, or
|
|
}
|
|
|
|
// PushVid 推送视频
|
|
func PushVid(req pushmod.AddReq) (code stderr.Code, data interface{}) {
|
|
oid, err := primitive.ObjectIDFromHex(req.VideoID)
|
|
if err != nil {
|
|
log.Error("PushVid error", log.Any("req", req), log.E(err))
|
|
return stderr.ErrParamError, nil
|
|
}
|
|
doc := pushmod.PushModel{
|
|
VideoID: oid,
|
|
Title: req.Title,
|
|
Type: vidmod.SP,
|
|
CreatedAt: time.Now(),
|
|
}
|
|
if err = pushmod.InsertOne(doc); err != nil {
|
|
return stderr.ErrDbInsertError, ""
|
|
}
|
|
return stderr.Success, nil
|
|
}
|
|
|
|
// PushVidList 获取推送列表
|
|
func PushVidList(req pushmod.ListReq) (code stderr.Code, data interface{}) {
|
|
cond := bson.M{}
|
|
if len(req.VideoID) != 0 {
|
|
oid, err := primitive.ObjectIDFromHex(req.VideoID)
|
|
if err != nil {
|
|
log.Error("PushVidList error", log.Any("req", req), log.E(err))
|
|
return stderr.ErrParamError, nil
|
|
}
|
|
cond = bson.M{"videoID": oid}
|
|
}
|
|
sort := bson.D{{Key: "createdAt", Value: -1}}
|
|
infos, _, total, err := pushmod.GetPushList(req.PageNumber, req.PageSize, cond, sort)
|
|
if err != nil {
|
|
return stderr.ErrDbQueryError, nil
|
|
}
|
|
return stderr.Success, pushmod.ListResp{VInfos: infos, Total: total}
|
|
}
|
|
|
|
// DeletePushVid 删除推送视频
|
|
func DeletePushVid(ids []string) (code stderr.Code, data interface{}) {
|
|
oids := make([]primitive.ObjectID, 0, len(ids))
|
|
for _, id := range ids {
|
|
oid, err := primitive.ObjectIDFromHex(id)
|
|
if err != nil {
|
|
log.Error("DeletePushVid error", log.Any("ids", ids), log.E(err))
|
|
continue
|
|
}
|
|
oids = append(oids, oid)
|
|
}
|
|
if oids == nil {
|
|
return stderr.ErrParamError, nil
|
|
}
|
|
cnt, err := pushmod.Delete(bson.M{"videoID": bson.M{"$in": oids}})
|
|
if err != nil {
|
|
return stderr.ErrDbDeleteError, ""
|
|
}
|
|
return stderr.Success, pushmod.OperateResult{Count: cnt}
|
|
}
|
|
|
|
// SyncFileFromFs 从文件服务器同步文件信息未审核通过
|
|
func SyncFileFromFsForNoPassed(vID string) (code stderr.Code) {
|
|
v, _ := vidmod.GetVideoInfo(vID)
|
|
resp, err := updownloadser.PullFileInfo(v.SourceID)
|
|
if err != nil {
|
|
return stderr.ErrConnectToFs
|
|
}
|
|
var resolution, actor, direction, quality string
|
|
oid, _ := primitive.ObjectIDFromHex(resp.Data.ID)
|
|
sourceID := resp.Data.ID
|
|
playTime := resp.Data.PlayTime
|
|
freeTime := vidmod.GetFreeTime(resp.Data.PlayTime)
|
|
if v.FreeTime != 0 && freeTime != v.FreeTime {
|
|
freeTime = v.FreeTime
|
|
}
|
|
seriesCover := resp.Data.CoverImg
|
|
width := resp.Data.Width
|
|
height := resp.Data.Height
|
|
if width != 0 && height != 0 {
|
|
resolution = strconv.FormatInt(int64(resp.Data.Width), 10) + "*" + strconv.FormatInt(int64(resp.Data.Height), 10)
|
|
identifi := common.IdentifiVideoInfo(int64(resp.Data.Width), int64(resp.Data.Height))
|
|
direction = string(identifi.Direction)
|
|
quality = string(identifi.Quality)
|
|
}
|
|
md5 := resp.Data.CheckSum
|
|
if len(resp.Data.Actors) > 0 {
|
|
actor = strings.Join(resp.Data.Actors, ",")
|
|
}
|
|
size := resp.Data.Size
|
|
filename := resp.Data.Filename
|
|
via := resp.Data.Via
|
|
ratio := resp.Data.Ratio
|
|
update := vidmod.WebVideoUpdateDoc{
|
|
ID: oid,
|
|
SourceID: &sourceID,
|
|
PlayTime: &playTime,
|
|
FreeTime: &freeTime,
|
|
SeriesCover: &seriesCover,
|
|
Resolution: &resolution,
|
|
Width: &width,
|
|
Height: &height,
|
|
MD5: &md5,
|
|
Actor: &actor,
|
|
Size: &size,
|
|
Filename: &filename,
|
|
Via: &via,
|
|
Ratio: &ratio,
|
|
Direction: &direction,
|
|
Quality: &quality,
|
|
}
|
|
if resp.Code == stderr.UpLoadFileComplete {
|
|
if v.Cover == "" {
|
|
cover := resp.Data.FieldNameFs + "-1.jpg"
|
|
update.Cover = &cover
|
|
}
|
|
if v.CoverThumb == "" {
|
|
coverThumb := resp.Data.FieldNameFs + "-2.jpg"
|
|
update.CoverThumb = &coverThumb
|
|
}
|
|
}
|
|
_, _ = vidmod.UpdateVideoResolutionPlayTime(v.ID, update)
|
|
return resp.Code
|
|
}
|
|
|
|
// SyncFileFromFs 从文件服务器同步文件信息
|
|
func SyncFileFromFs(vID string) (code stderr.Code) {
|
|
v, _ := vidmod.GetVideoInfo(vID)
|
|
resp, err := updownloadser.PullFileInfo(v.SourceID)
|
|
if err != nil {
|
|
return stderr.ErrConnectToFs
|
|
}
|
|
if resp.Code == stderr.UpLoadFileComplete {
|
|
oid, _ := primitive.ObjectIDFromHex(resp.Data.ID)
|
|
sourceID := resp.Data.ID
|
|
playTime := resp.Data.PlayTime
|
|
freeTime := vidmod.GetFreeTime(resp.Data.PlayTime)
|
|
if v.FreeTime != 0 && freeTime != v.FreeTime {
|
|
freeTime = v.FreeTime
|
|
}
|
|
seriesCover := resp.Data.CoverImg
|
|
resolution := strconv.FormatInt(int64(resp.Data.Width), 10) + "*" + strconv.FormatInt(int64(resp.Data.Height), 10)
|
|
width := resp.Data.Width
|
|
height := resp.Data.Height
|
|
identifi := common.IdentifiVideoInfo(int64(resp.Data.Width), int64(resp.Data.Height))
|
|
direction := string(identifi.Direction)
|
|
quality := string(identifi.Quality)
|
|
md5 := resp.Data.CheckSum
|
|
actor := strings.Join(resp.Data.Actors, ",")
|
|
size := resp.Data.Size
|
|
filename := resp.Data.Filename
|
|
via := resp.Data.Via
|
|
ratio := resp.Data.Ratio
|
|
update := vidmod.WebVideoUpdateDoc{
|
|
ID: oid,
|
|
SourceID: &sourceID,
|
|
PlayTime: &playTime,
|
|
FreeTime: &freeTime,
|
|
VideoCover: &seriesCover,
|
|
Resolution: &resolution,
|
|
Width: &width,
|
|
Height: &height,
|
|
MD5: &md5,
|
|
Actor: &actor,
|
|
Size: &size,
|
|
Filename: &filename,
|
|
Via: &via,
|
|
Ratio: &ratio,
|
|
Direction: &direction,
|
|
Quality: &quality,
|
|
}
|
|
if v.Cover == "" {
|
|
cover := resp.Data.FieldNameFs + "-1.jpg"
|
|
update.Cover = &cover
|
|
}
|
|
if v.CoverThumb == "" {
|
|
coverThumb := resp.Data.FieldNameFs + "-2.jpg"
|
|
update.CoverThumb = &coverThumb
|
|
}
|
|
if v.SeriesCover == nil || len(v.SeriesCover) <= 0 {
|
|
update.SeriesCover = &seriesCover
|
|
}
|
|
_, _ = vidmod.UpdateVideoResolutionPlayTime(v.ID, update)
|
|
}
|
|
return resp.Code
|
|
}
|
|
|
|
// SyncBaseInfoFromFs 从文件服务器同步基本信息
|
|
func SyncBaseInfoFromFs(vID string) (code stderr.Code) {
|
|
oid, _ := primitive.ObjectIDFromHex(vID)
|
|
resp, err := updownloadser.PullFileInfo(vID)
|
|
if err != nil {
|
|
return stderr.ErrConnectToFs
|
|
}
|
|
if resp.Code == stderr.UpLoadFileComplete {
|
|
update := vidmod.WebSyncServerFileEdit{
|
|
PlayTime: resp.Data.PlayTime,
|
|
Resolution: strconv.FormatInt(int64(resp.Data.Width), 10) + "*" + strconv.FormatInt(int64(resp.Data.Height), 10),
|
|
MD5: resp.Data.CheckSum,
|
|
Size: resp.Data.Size,
|
|
Ratio: resp.Data.Ratio,
|
|
}
|
|
set, _ := common.ToBsonM(update)
|
|
if _, err = vidmod.UpdateVideoByMapCond(oid, set); err != nil {
|
|
return stderr.Failure
|
|
}
|
|
}
|
|
return resp.Code
|
|
}
|
|
|
|
// 查看视频转码状态
|
|
func ViewVideoFromFs(id string) (code stderr.Code, data interface{}) {
|
|
resp, err := updownloadser.PullFileInfo(id)
|
|
if err != nil {
|
|
return stderr.ErrConnectToFs, nil
|
|
}
|
|
back := make(map[string]interface{}, 10)
|
|
back["playTime"] = resp.Data.PlayTime
|
|
back["size"] = resp.Data.Size
|
|
back["width"] = resp.Data.Width
|
|
back["height"] = resp.Data.Height
|
|
back["status"] = resp.Data.Status
|
|
back["ratio"] = resp.Data.Ratio
|
|
fileName := resp.Data.Filename
|
|
fieldNameFs := resp.Data.FieldNameFs
|
|
back["fileName"] = filepath.Join(filepath.Dir(fieldNameFs), fileName)
|
|
switch resp.Data.Status {
|
|
case vidmod.UploadLoadingToFs:
|
|
back["statusDesc"] = "正在上传中"
|
|
case vidmod.UploadCompleted:
|
|
back["statusDesc"] = "上传完成"
|
|
case vidmod.FileUploadError:
|
|
back["statusDesc"] = "上传错误"
|
|
case vidmod.Merging:
|
|
back["statusDesc"] = "正在合并中"
|
|
case vidmod.MergeCompleted:
|
|
back["statusDesc"] = "合并完成"
|
|
case vidmod.MergeError:
|
|
back["statusDesc"] = "合并失败"
|
|
case vidmod.Converting:
|
|
back["statusDesc"] = "正在转码中"
|
|
case vidmod.ConvertError:
|
|
back["statusDesc"] = "转码失败"
|
|
case vidmod.ConvertCompleted, vidmod.Completed:
|
|
back["statusDesc"] = "完成状态"
|
|
}
|
|
return stderr.Success, back
|
|
}
|
|
|
|
type (
|
|
GetVideoListByTagReq struct {
|
|
TagID string `form:"tagID" json:"tagID" binding:"required"` // 标签ID
|
|
SortType int `form:"sortType" json:"sortType" binding:"required"` // 排序类型 1:最新上架 2:最多收藏 3:本月最热 4:最多观看
|
|
NewsType string `json:"newsType" form:"newsType" binding:"-"` // 帖子类型: SP、SHORT、COVER
|
|
commod.Page
|
|
}
|
|
GetVideoListByTagRep struct {
|
|
List []*vidmod.VideoInfo `json:"list"` // 视频列表
|
|
HasNext bool `json:"hasNext"` // 是否还有下一页
|
|
}
|
|
)
|
|
|
|
// GetVideoListByTag 通过标签id获取视频列表信息
|
|
func (req *GetVideoListByTagReq) GetVideoListByTag() (rep GetVideoListByTagRep, err error) {
|
|
excludedModuleIDs, err := excludedTagSearchModuleIDs()
|
|
if err != nil {
|
|
return rep, err
|
|
}
|
|
redisKey := tagSearchCacheKey(
|
|
redisconst.GetTagSortVideoKey(req.TagID, req.NewsType, req.SortType, req.Skip(), req.Limit()),
|
|
excludedModuleIDs,
|
|
)
|
|
s, err := appg.Redis.Get(redisKey)
|
|
if err != nil {
|
|
log.Error("GetVideoListByTag redis get error", log.E(err), log.Any("req", req))
|
|
}
|
|
if s != nil && *s != "" {
|
|
err = json.Unmarshal([]byte(*s), &rep)
|
|
if err == nil {
|
|
return rep, nil
|
|
}
|
|
log.Error("GetVideoListByTag json unmarshal error", log.E(err), log.Any("val", *s))
|
|
}
|
|
// --------
|
|
tid, _ := primitive.ObjectIDFromHex(req.TagID)
|
|
filter := bson.M{
|
|
"tags": tid,
|
|
"status": 1, //状态,0 未审核 1通过 2审核失败 3视为免费 默认为0
|
|
}
|
|
applyTagSearchVisibilityFilter(filter, excludedModuleIDs)
|
|
|
|
if req.NewsType != "" {
|
|
filter["newsType"] = req.NewsType
|
|
}
|
|
|
|
// 本项目用到以下3个
|
|
//1: 最新:按最新上架时间
|
|
//2: 收藏:按总收藏量排序
|
|
//4: 观看:播放量最多的数据
|
|
var sortCond bson.D
|
|
switch req.SortType {
|
|
case 2:
|
|
sortCond = bson.D{{Key: "collectCount", Value: -1}, {Key: "reviewAt", Value: -1}}
|
|
case 3:
|
|
filter["reviewAt"] = bson.M{"$gte": time.Now().AddDate(0, -3, 0)}
|
|
sortCond = bson.D{{Key: "likeCount", Value: -1}, {Key: "reviewAt", Value: -1}}
|
|
case 4:
|
|
sortCond = bson.D{{"playCount", -1}, {Key: "reviewAt", Value: -1}}
|
|
case 5:
|
|
sortCond = bson.D{{Key: "hot", Value: -1}, {Key: "reviewAt", Value: -1}}
|
|
case 1: // 最新
|
|
fallthrough
|
|
default:
|
|
sortCond = bson.D{{Key: "reviewAt", Value: -1}}
|
|
}
|
|
|
|
opt := options.Find().
|
|
SetSkip(int64(req.Skip())).
|
|
SetLimit(int64(req.Limit())).
|
|
SetProjection(bson.M{"chosenDate": 0}).
|
|
SetSort(sortCond)
|
|
|
|
out, next, err := vidmod.FindList(filter, opt)
|
|
if err != nil {
|
|
return rep, err
|
|
}
|
|
|
|
rep.HasNext = next
|
|
rep.List = vidhelpser.EncodeVideoInfoNoUID(out)
|
|
|
|
go func() {
|
|
b, _ := json.Marshal(rep)
|
|
_ = appg.Redis.Set(redisKey, string(b), redisconst.GetTagSortVideoExpire())
|
|
}()
|
|
|
|
return rep, nil
|
|
}
|
|
|
|
// BatchAuditVidTimeOnlineInfo 批量新增自动上架视频信息
|
|
func BatchAuditVidTimeOnlineInfo(req vidtimeonlinemod.BatchAuditReq, price int, manager string) (code stderr.Code, data interface{}) {
|
|
if len(req.Vids) > 20 {
|
|
return stderr.BatchAuditLengthTooLong, nil
|
|
}
|
|
// 定时上架前置敏感词校验
|
|
if err := CheckShelvingByIDs(req.Vids); err != nil {
|
|
return stderr.ContentSensitiveHit, err.Error()
|
|
}
|
|
//now := time.Now()
|
|
//if !req.OnlineTime.After(now) {
|
|
// req.OnlineTime = now
|
|
//}
|
|
// 获取专题
|
|
section, err := modulesectionmod.GetBySectionByID(req.SectionID)
|
|
if err != nil {
|
|
return stderr.ErrDbQueryError, nil
|
|
}
|
|
var adds []vidtimeonlinemod.VidTimeOnlineModel
|
|
var updateIds []primitive.ObjectID
|
|
var reErr stderr.Code
|
|
var vIds []primitive.ObjectID
|
|
reErr = stderr.Success
|
|
for _, id := range req.Vids {
|
|
vid, _ := primitive.ObjectIDFromHex(id.Hex())
|
|
//查询视频信息
|
|
vidInfo, err := vidmod.FindOneByFilter(bson.M{"_id": vid})
|
|
if err != nil {
|
|
log.Error("AddVidTimeOnlineInfo vidmod.FindOneByFilter error", log.Any("req", req), log.Any("err", err))
|
|
reErr = stderr.ErrDbQueryError
|
|
break
|
|
}
|
|
if vidInfo == nil || vidInfo.ID.IsZero() {
|
|
reErr = stderr.VidNotExists
|
|
break
|
|
}
|
|
|
|
// 取消限制长视频
|
|
//if vidInfo.PlayTime > 300 && vidInfo.PublisherID > 150000 {
|
|
// return stderr.OnlyOfficialVideo, nil
|
|
//}
|
|
|
|
// 自动上架支持类型短视频、帖子、长视频
|
|
if vidInfo.NewsType != vidmod.SP && vidInfo.NewsType != vidmod.COVER && vidInfo.NewsType != vidmod.SHORT {
|
|
reErr = stderr.VideoTypeDissatisfy
|
|
return reErr, nil
|
|
}
|
|
if len(vidInfo.Tags) <= 0 {
|
|
return stderr.VideoTagNoExists, nil
|
|
}
|
|
//查询上传用户信息
|
|
publisherInfo, err1 := usermod.FindUserByUID(vidInfo.PublisherID)
|
|
if err1 != nil {
|
|
log.Error("AddVidTimeOnlineInfo usermod.FindUserByUID error", log.Any("req", req), log.Any("err", err), log.Any("publisherID", vidInfo.PublisherID))
|
|
//reErr = stderr.ErrDbQueryError
|
|
continue
|
|
}
|
|
// 查询该帖子是否已经在定时上架列表,如果存在则更新
|
|
videos, err := vidtimeonlinemod.GetByVidIds([]primitive.ObjectID{vidInfo.ID})
|
|
if err != nil {
|
|
return stderr.ErrDbQueryError, nil
|
|
}
|
|
vIds = append(vIds, vidInfo.ID)
|
|
if len(videos) > 0 {
|
|
// 不需要添加只需要修改上线时间
|
|
updateIds = append(updateIds, vidInfo.ID)
|
|
} else {
|
|
add := vidtimeonlinemod.VidTimeOnlineModel{
|
|
ID: primitive.NewObjectID(),
|
|
PublisherID: vidInfo.PublisherID,
|
|
Portrait: publisherInfo.Portrait,
|
|
VidType: vidInfo.NewsType,
|
|
VidId: vidInfo.ID,
|
|
VidTitle: vidInfo.Title,
|
|
Cover: vidInfo.Cover,
|
|
CreatedAt: time.Now(),
|
|
ReviewAccount: manager,
|
|
OnlineTime: req.OnlineTime,
|
|
SectionId: req.SectionID,
|
|
}
|
|
if vidInfo.NewsType == vidmod.SP || vidInfo.NewsType == vidmod.SHORT {
|
|
add.SourceURL = vidInfo.SourceURL
|
|
} else {
|
|
add.SeriesCover = vidInfo.SeriesCover
|
|
}
|
|
adds = append(adds, add)
|
|
}
|
|
reErr = stderr.Success
|
|
}
|
|
if reErr != stderr.Success {
|
|
return reErr, nil
|
|
}
|
|
if len(adds) > 0 {
|
|
err := vidtimeonlinemod.InsertMany(adds)
|
|
if err != nil {
|
|
log.Error("AddVidTimeOnlineInfo vidTimeOnlineMod InsertMany error", log.Any("err", err))
|
|
return stderr.ErrDbInsertError, nil
|
|
}
|
|
}
|
|
if len(updateIds) > 0 {
|
|
updateData := bson.M{
|
|
"onlineTime": req.OnlineTime,
|
|
}
|
|
if !section.ID.IsZero() {
|
|
updateData["sectionId"] = section.ID
|
|
}
|
|
err := vidtimeonlinemod.UpdateMany(updateIds, updateData)
|
|
if err != nil {
|
|
log.Error("AddVidTimeOnlineInfo vidTimeOnlineMod UpdateMany error", log.Any("err", err))
|
|
return stderr.ErrDbInsertError, nil
|
|
}
|
|
}
|
|
if len(vIds) > 0 {
|
|
// 批量更新视频信息
|
|
update := bson.M{}
|
|
update["updatedAt"] = time.Now()
|
|
update["status"] = vidmod.OnlinePass // 定时贴上架标记
|
|
applyScheduledVideoModuleID(update, section.SubModuleID)
|
|
if price >= 0 {
|
|
update["coins"] = price
|
|
}
|
|
result, err := vidmod.UpdateManyVideo(vIds, update)
|
|
if err != nil {
|
|
return stderr.Failure, err
|
|
}
|
|
if result == 0 {
|
|
return stderr.Failure, errors.New("video update failed")
|
|
}
|
|
}
|
|
return stderr.Success, nil
|
|
}
|
|
|
|
func applyScheduledVideoModuleID(update bson.M, moduleID primitive.ObjectID) {
|
|
if !moduleID.IsZero() {
|
|
update["mId"] = moduleID.Hex()
|
|
}
|
|
}
|
|
|
|
// GetTimeOnlineVidList 获取定时上线视频列表
|
|
func GetTimeOnlineVidList(req *vidtimeonlinemod.ListReq) (code stderr.Code, data interface{}) {
|
|
var err error
|
|
cond := bson.M{}
|
|
res := gin.H{"vidModels": "", "total": 0}
|
|
if req.UID > 0 {
|
|
cond["publisherID"] = req.UID
|
|
}
|
|
if req.VidId != "" {
|
|
vid, _ := primitive.ObjectIDFromHex(req.VidId)
|
|
cond["vidId"] = vid
|
|
}
|
|
|
|
if req.Tag != nil {
|
|
id, err := tagmod.GetTagIDByName(*req.Tag)
|
|
if err != nil {
|
|
return stderr.ErrDbQueryError, res
|
|
}
|
|
cond["tags"] = id
|
|
}
|
|
|
|
vidModels, total, err := vidtimeonlinemod.GetAllByPage(cond, req.Page)
|
|
if err != nil {
|
|
return stderr.ErrDbQueryError, res
|
|
}
|
|
var (
|
|
tags []primitive.ObjectID
|
|
resp []vidtimeonlinemod.VidTimeOnlineModelResp
|
|
)
|
|
|
|
if len(vidModels) > 0 {
|
|
for _, v := range vidModels {
|
|
tags = append(tags, v.Tags...)
|
|
}
|
|
|
|
} else {
|
|
return stderr.Success, res
|
|
}
|
|
mTags := vidhelp.GetTagsByIDs2Map(tags)
|
|
|
|
for _, v := range vidModels {
|
|
t := vidhelp.GetPartTags(v.Tags, mTags)
|
|
resp = append(resp, vidtimeonlinemod.VidTimeOnlineModelResp{
|
|
ID: v.ID,
|
|
Tags: t,
|
|
VidType: v.VidType,
|
|
PublisherID: v.PublisherID,
|
|
Portrait: v.Portrait,
|
|
VidTitle: v.VidTitle,
|
|
VidId: v.VidId,
|
|
OnlineSort: v.OnlineSort,
|
|
SourceURL: v.SourceURL,
|
|
Cover: v.Cover,
|
|
SeriesCover: v.SeriesCover,
|
|
OnlineTime: v.OnlineTime,
|
|
CreatedAt: v.CreatedAt,
|
|
ReviewAccount: v.ReviewAccount,
|
|
SectionId: v.SectionId,
|
|
})
|
|
}
|
|
|
|
res["total"] = total
|
|
res["vidModels"] = resp
|
|
return stderr.Success, res
|
|
}
|
|
|
|
// DeleteTimeOnlineVid 删除定时上线视频
|
|
func DeleteTimeOnlineVid(ids []primitive.ObjectID) (code stderr.Code) {
|
|
list, err := vidtimeonlinemod.GetByVidIds(ids)
|
|
if err != nil {
|
|
return stderr.ErrDbQueryError
|
|
}
|
|
vids := []primitive.ObjectID{}
|
|
for _, v := range list {
|
|
vids = append(vids, v.VidId)
|
|
}
|
|
err = vidtimeonlinemod.DeleteByIds(ids)
|
|
if err != nil {
|
|
return stderr.ErrDbDeleteError
|
|
}
|
|
// 把帖子状态更新为下架
|
|
err = vidmod.UpdateMany(bson.M{"_id": bson.M{"$in": vids}}, bson.M{"$set": bson.M{"status": vidmod.CheckFailure}})
|
|
if err != nil {
|
|
return stderr.ErrDbDeleteError
|
|
}
|
|
return stderr.Success
|
|
|
|
}
|
|
|
|
// UpdateVidNewsType 批量修改帖子类型
|
|
func UpdateVidNewsType(req vidmod.BatchUpdateVidNewsTypeReq) (code stderr.Code) {
|
|
newsTypeList := []string{
|
|
vidmod.SP,
|
|
vidmod.SHORT,
|
|
vidmod.PIC,
|
|
vidmod.COVER,
|
|
vidmod.AD_COVER,
|
|
vidmod.AD_SP,
|
|
vidmod.SEED_LINK,
|
|
}
|
|
if !slice.Contains(newsTypeList, req.NewsType) {
|
|
return stderr.ErrParamError
|
|
}
|
|
err := vidmod.UpdateVideosByMapCond(req.Ids, bson.M{
|
|
"newsType": req.NewsType,
|
|
})
|
|
if err != nil {
|
|
log.Error("UpdateVideosByMapCond error", log.Any("req", req), log.E(err))
|
|
}
|
|
return stderr.Success
|
|
}
|
|
|
|
// UpdateVidTags 批量更新视频信息
|
|
func UpdateVidTags(req vidmod.EditVideTagsReq) (code stderr.Code) {
|
|
if len(req.Ids) <= 0 || len(req.Tags) <= 0 {
|
|
return stderr.ErrParamError
|
|
}
|
|
|
|
ids := make([]primitive.ObjectID, 0, len(req.Ids))
|
|
for _, id := range req.Ids {
|
|
oid, err := primitive.ObjectIDFromHex(id)
|
|
if err != nil {
|
|
log.Error("UpdateVids error", log.Any("req", req), log.E(err))
|
|
continue
|
|
}
|
|
ids = append(ids, oid)
|
|
}
|
|
|
|
// 获取相关视频
|
|
videoList, err := vidmod.GetVideoListByIDsNoStatus(ids)
|
|
if err != nil {
|
|
log.Error(fmt.Sprintf("UpdateVidTags vidmod.GetVideoListByIDsNoStatus err:%v, ids:%v", err, req.Ids))
|
|
return
|
|
}
|
|
var newTags []primitive.ObjectID
|
|
var oldTags []primitive.ObjectID
|
|
update := bson.M{"updatedAt": time.Now()}
|
|
|
|
if req.Tags != nil {
|
|
newTags = vidhelp.AddTags(req.Ids[0], req.Tags)
|
|
}
|
|
|
|
for _, v := range videoList {
|
|
oldTags = v.Tags
|
|
// 获取旧的tags
|
|
if req.Overwrite {
|
|
update["tags"] = newTags
|
|
} else {
|
|
update["tags"] = sli.RemoveRep(append(v.Tags, newTags...))
|
|
}
|
|
|
|
// 修改视频tag
|
|
_, err = vidmod.UpdateOneByID(v.ID, update)
|
|
if err != nil {
|
|
log.Error(fmt.Sprintf("UpdateVidTags vidmod.UpdateOneByID err:%v, id:%v, update: %v", err, v.ID, update))
|
|
continue
|
|
}
|
|
// 修改旧tag与新tag的视频数量
|
|
updateTagVideoCnt(oldTags, newTags)
|
|
}
|
|
return stderr.Success
|
|
}
|