418 lines
11 KiB
Go
418 lines
11 KiB
Go
package vidhelp
|
|
|
|
import (
|
|
"91porn-server/models/v/moduleconfmod"
|
|
"91porn-server/models/v/modulesectionmod"
|
|
"errors"
|
|
"math"
|
|
"reflect"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"91porn-server/common/crypt"
|
|
"91porn-server/common/log"
|
|
sli "91porn-server/common/slice"
|
|
v10 "91porn-server/common/v10"
|
|
"91porn-server/models/l/payvidlgmod"
|
|
"91porn-server/models/v/modulevidmod"
|
|
"91porn-server/models/v/pushmod"
|
|
"91porn-server/models/v/tagmod"
|
|
"91porn-server/models/v/usermod"
|
|
"91porn-server/models/v/vidmod"
|
|
|
|
"github.com/shopspring/decimal"
|
|
"go.mongodb.org/mongo-driver/bson/primitive"
|
|
)
|
|
|
|
// OID 别名
|
|
type OID = primitive.ObjectID
|
|
|
|
// Struct2Map 结构体转map
|
|
func Struct2Map(obj interface{}) map[string]interface{} {
|
|
t := reflect.TypeOf(obj)
|
|
v := reflect.ValueOf(obj)
|
|
var data = make(map[string]interface{})
|
|
for i := 0; i < t.NumField(); i++ {
|
|
key, ok := t.Field(i).Tag.Lookup("json")
|
|
if !ok {
|
|
log.Error("Struct2Map error", log.Any("obj", obj))
|
|
continue
|
|
}
|
|
data[key] = v.Field(i).Interface()
|
|
}
|
|
data["updatedAt"] = time.Now()
|
|
return data
|
|
}
|
|
|
|
// AddTags 没有的tag就添加
|
|
func AddTags(id string, tagNames []string) []primitive.ObjectID {
|
|
back := []primitive.ObjectID{}
|
|
cover, err := vidmod.GetVideoCover(id)
|
|
if err != nil {
|
|
return back
|
|
}
|
|
back = make([]primitive.ObjectID, 0, len(tagNames))
|
|
for _, n := range tagNames {
|
|
tMod := tagmod.Tag{
|
|
TagName: v10.ExtractPureChar(n),
|
|
CoverImg: cover,
|
|
Description: "",
|
|
SortCode: 0,
|
|
VPlayCount: 0,
|
|
TPlayCount: 0,
|
|
FakePlayCount: 0,
|
|
FakeCollCount: 0,
|
|
IsActive: true,
|
|
CreatedAt: time.Now(),
|
|
UpdatedAt: time.Now(),
|
|
}
|
|
data, err := tagmod.FindOneTagByName(v10.ExtractPureChar(n))
|
|
if err != nil {
|
|
log.Error("AddTags FindOneTagByName error", log.Any("id", id), log.Any("tagNames", tagNames), log.E(err))
|
|
continue
|
|
}
|
|
if data.ID.IsZero() {
|
|
oid, err := tagmod.InsertOne(&tMod)
|
|
if err != nil {
|
|
log.Error("AddTags InsertOne error", log.Any("id", id), log.Any("tagNames", tagNames), log.E(err))
|
|
} else {
|
|
back = append(back, oid)
|
|
}
|
|
continue
|
|
}
|
|
back = append(back, data.ID)
|
|
}
|
|
return back
|
|
}
|
|
|
|
// GetTagsByIDs2Map 通过tagid列表获取tag详情列表
|
|
func GetTagsByIDs2Map(ids []OID) map[primitive.ObjectID]vidmod.TagInfo {
|
|
m := make(map[primitive.ObjectID]vidmod.TagInfo)
|
|
tags, err := tagmod.FindTagsByIDS(ids)
|
|
if err != nil {
|
|
log.Error("GetTagsByIDs2Map error", log.Any("ids", ids), log.E(err))
|
|
return m
|
|
}
|
|
for _, info := range tags {
|
|
b := vidmod.TagInfo{
|
|
ID: info.ID,
|
|
Name: info.TagName,
|
|
CoverImg: info.CoverImg,
|
|
Description: info.Description,
|
|
}
|
|
m[info.ID] = b
|
|
}
|
|
return m
|
|
}
|
|
|
|
// GetPartTags 从内存获取tagInfo
|
|
func GetPartTags(ids []OID, mTags map[primitive.ObjectID]vidmod.TagInfo) []vidmod.TagInfo {
|
|
infos := make([]vidmod.TagInfo, len(ids))
|
|
for i, v := range ids {
|
|
infos[i] = mTags[v]
|
|
}
|
|
return infos
|
|
}
|
|
|
|
// Transfer2Info 将视频数据库模式转为返回模式
|
|
func transfer2Info(v *vidmod.VideoModel, uInfo usermod.BaseInfo, ti []vidmod.TagInfo, pushing bool) *vidmod.WebVideo {
|
|
isUser := false
|
|
if v.PublisherID > 115000 {
|
|
isUser = true
|
|
}
|
|
chosen := false
|
|
if v.Chosen {
|
|
chosen = v.Chosen
|
|
}
|
|
freeArea := false
|
|
if v.FreeArea {
|
|
freeArea = v.FreeArea
|
|
}
|
|
coins := v.Coins
|
|
if v.Status == 0 && coins == vidmod.PretendAccInitCoins {
|
|
coins = vidmod.PretendAccDefaultCoins
|
|
}
|
|
newsType := vidmod.SP
|
|
if len(v.NewsType) != 0 {
|
|
newsType = v.NewsType
|
|
}
|
|
tags := make([]string, len(ti))
|
|
for i, tag := range ti {
|
|
tags[i] = tag.Name
|
|
}
|
|
return &vidmod.WebVideo{
|
|
ID: v.ID,
|
|
NewsType: newsType,
|
|
Publisher: uInfo,
|
|
PubliserID: uInfo.UID,
|
|
PublisherName: uInfo.Name,
|
|
Title: v.Title,
|
|
Content: v.Content,
|
|
Tags: ti,
|
|
Cover: v.Cover,
|
|
CoverThumb: v.CoverThumb,
|
|
SeriesCover: v.SeriesCover,
|
|
IsUser: isUser,
|
|
PlayCount: v.PlayCount,
|
|
Status: v.Status,
|
|
PlayTime: v.PlayTime,
|
|
LikeCount: v.LikeCount,
|
|
Resolution: v.Resolution,
|
|
CommentCount: v.CommentCount,
|
|
ShareCount: v.ShareCount,
|
|
FakeLikeCount: v.FakeLikeCount,
|
|
FakeCommentCount: v.FakeCommentCount,
|
|
FakeShareCount: v.FakeShareCount,
|
|
FakePlayCount: v.FakePlayCount,
|
|
Coins: coins,
|
|
CreatedAt: v.CreatedAt,
|
|
UpdatedAt: v.UpdatedAt,
|
|
FreeTime: v.FreeTime,
|
|
SourceID: v.SourceID,
|
|
SourceURL: v.SourceURL,
|
|
LinkUrl: v.LinkUrl,
|
|
PreviewURL: v.PreviewURL,
|
|
SortCode: v.SortCode,
|
|
FileName: v.Filename,
|
|
Chosen: chosen,
|
|
FreeArea: freeArea,
|
|
Pushing: pushing,
|
|
Size: v.Size,
|
|
Reason: v.Reason,
|
|
IsTopping: v.IsTopping,
|
|
IsRecommend: v.IsRecommend,
|
|
IsChoosen: v.IsChoosen,
|
|
RecoWeight: v.RecoWeight,
|
|
ReviewAccount: v.ReviewAccount,
|
|
Rewarded: v.Rewarded,
|
|
FakeRewarded: v.FakeRewarded,
|
|
TagSort: coverTagSort(v.TagSort, ti),
|
|
LiaoBaTop: v.LiaoBaTop,
|
|
LiaoBaTopSort: v.LiaoBaTopSort,
|
|
WorksSort: v.WorksSort,
|
|
PageViewCount: v.PageViewCount,
|
|
TagsExport: strings.Join(tags, "|"),
|
|
ActivityID: v.ActivityID,
|
|
HappinessPlazaTop: v.HappinessPlazaTop,
|
|
ShareSort: v.ShareSort,
|
|
TimeNodeList: v.TimeNodeList,
|
|
DownloadAllow: v.DownloadAllow,
|
|
ShowType: v.ShowType,
|
|
}
|
|
}
|
|
|
|
func coverTagSort(id interface{}, ti []vidmod.TagInfo) []vidmod.TagSort {
|
|
tagSort := []vidmod.TagSort{}
|
|
tagInfo := make(map[string]int)
|
|
type keyValue struct {
|
|
Key string
|
|
Value int
|
|
}
|
|
xx := []keyValue{}
|
|
if err := crypt.Obj2Obj(id, &xx); err != nil {
|
|
return tagSort
|
|
}
|
|
if len(ti) > 0 {
|
|
ids := make([]string, len(xx))
|
|
for i, v := range xx {
|
|
ids[i] = v.Key
|
|
tagInfo[v.Key] = v.Value
|
|
}
|
|
tagSort = make([]vidmod.TagSort, len(ti))
|
|
for i, v := range ti {
|
|
var sortCode int
|
|
if sli.Contains(ids, v.ID.Hex()) {
|
|
sortCode = tagInfo[v.ID.Hex()]
|
|
}
|
|
tagSort[i] = vidmod.TagSort{
|
|
TagId: v.ID.Hex(),
|
|
TagName: v.Name,
|
|
SortCode: sortCode,
|
|
}
|
|
}
|
|
}
|
|
return tagSort
|
|
}
|
|
|
|
// GetUserInfo2Map 获取用户基本信息到map
|
|
func GetUserInfo2Map(uids []uint64) map[uint64]*usermod.BaseInfo {
|
|
userInfo, err := usermod.GetUsersBaseInfo(uids)
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
m := make(map[uint64]*usermod.BaseInfo)
|
|
for _, i := range userInfo {
|
|
m[i.UID] = i
|
|
}
|
|
return m
|
|
}
|
|
|
|
// IsPushing 是否推送
|
|
func IsPushing(id primitive.ObjectID) bool {
|
|
push, _ := pushmod.IsExist(id)
|
|
return push
|
|
}
|
|
|
|
// EncodeVideoInfo 封装返回的视频列表信息
|
|
func EncodeVideoInfo(vInfos []*vidmod.VideoModel, secID primitive.ObjectID) (back []*vidmod.WebVideo, err error) {
|
|
vInfosLen := len(vInfos)
|
|
if vInfosLen == 0 {
|
|
return
|
|
}
|
|
uids := make([]uint64, vInfosLen)
|
|
var tags []primitive.ObjectID
|
|
videoIDs := make([]primitive.ObjectID, vInfosLen)
|
|
for i, v := range vInfos {
|
|
uids[i] = v.PublisherID
|
|
tags = append(tags, v.Tags...)
|
|
videoIDs[i] = v.ID
|
|
}
|
|
videoSalesStat, err := payvidlgmod.VideoCoinIncomeAggregateByVideoIDs(videoIDs)
|
|
if err != nil {
|
|
log.Error("VideoCoinIncomeAggregateByVideoIDs", log.E(err))
|
|
return
|
|
}
|
|
videoSalesMap := map[primitive.ObjectID]payvidlgmod.VideoCoinIncome{}
|
|
for _, stat := range videoSalesStat {
|
|
videoSalesMap[stat.VID] = stat
|
|
}
|
|
videos, err := modulevidmod.GetBySectionIDAndVids(secID, videoIDs)
|
|
if err != nil {
|
|
log.Error("GetBySectionIDAndVids", log.E(err))
|
|
return
|
|
}
|
|
videoMap := map[primitive.ObjectID]modulevidmod.SectionVideo{}
|
|
videoSectionMap := map[primitive.ObjectID]modulesectionmod.Section{}
|
|
moduleMap := map[primitive.ObjectID]moduleconfmod.ModuleConf{}
|
|
|
|
var secId []primitive.ObjectID
|
|
var moduleId []primitive.ObjectID
|
|
for _, v := range videos {
|
|
videoMap[v.VideoID] = v
|
|
secId = append(secId, v.SectionID)
|
|
}
|
|
|
|
// 获取专题信息
|
|
if len(secId) > 0 {
|
|
sections, err := modulesectionmod.GetBySectionByIDs(secId)
|
|
if err != nil {
|
|
log.Error("moduleSection GetBySectionByIDs err", log.E(err))
|
|
return nil, errors.New("moduleSection GetBySectionByIDs err")
|
|
}
|
|
if len(sections) > 0 {
|
|
for _, v := range videos {
|
|
for _, s := range sections {
|
|
if v.SectionID == s.ID {
|
|
videoSectionMap[v.VideoID] = s
|
|
moduleId = append(moduleId, s.SubModuleID)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// 获取模块信息
|
|
if len(moduleId) > 0 {
|
|
moduleConfs, err := moduleconfmod.FindByIDs(moduleId)
|
|
if err != nil {
|
|
log.Error("moduleConf FindByIDs err", log.E(err))
|
|
return nil, errors.New("moduleConf FindByIDs err")
|
|
}
|
|
|
|
if len(moduleConfs) > 0 {
|
|
for _, s := range sections {
|
|
for _, m := range moduleConfs {
|
|
if s.SubModuleID == m.ID {
|
|
moduleMap[s.ID] = m
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
mUser, _ := usermod.GetUsersBaseInfoMap(uids)
|
|
mTags := GetTagsByIDs2Map(tags)
|
|
back = make([]*vidmod.WebVideo, len(vInfos))
|
|
for i, v := range vInfos {
|
|
var uInfo usermod.BaseInfo
|
|
if mUser[v.PublisherID] != nil {
|
|
uInfo = *mUser[v.PublisherID]
|
|
}
|
|
info := transfer2Info(v, uInfo, GetPartTags(v.Tags, mTags), IsPushing(v.ID))
|
|
info.TotalSellAmount = videoSalesMap[v.ID].Total
|
|
info.TotalSellCount = videoSalesMap[v.ID].Count
|
|
info.TotalSellDays = CalculateVideoSellDays(v.ReviewAt)
|
|
info.PurchaseRate = CalculatePurchaseRate(videoSalesMap[v.ID].Count, int64(v.PlayCount))
|
|
info.HitRate = CalculateClickRate(int64(info.PlayCount), info.PageViewCount)
|
|
info.LikeRate = CalculateLikeRate(int64(info.LikeCount), int64(info.PlayCount))
|
|
info.SectionID = secID
|
|
info.SortCodeUnderSection = videoMap[v.ID].SortCode
|
|
info.ReviewAt = v.ReviewAt
|
|
info.SeedSize = v.SeedSize
|
|
info.SeedLinkUrl = v.SeedLinkUrl
|
|
info.SeedPlayTime = v.SeedPlayTime
|
|
info.RichText = v.RichText
|
|
info.PreviewStart = v.PreviewStart
|
|
info.SectionName = videoSectionMap[v.ID].SectionName
|
|
|
|
back[i] = info
|
|
if !videoSectionMap[v.ID].ID.IsZero() {
|
|
info.ModuleName = moduleMap[videoSectionMap[v.ID].ID].ModuleName
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
// IncCommentCount 评论统计次数加加
|
|
func IncCommentCount(id primitive.ObjectID) error {
|
|
if err := vidmod.IncCommentCount(id); err != nil {
|
|
return err
|
|
}
|
|
incComment(id)
|
|
return nil
|
|
}
|
|
|
|
// DecCommentCount 评论统计次数减少
|
|
func DecCommentCount(id primitive.ObjectID) error {
|
|
if err := vidmod.DecCommentCount(id, -1); err != nil {
|
|
return err
|
|
}
|
|
decComment(id)
|
|
return nil
|
|
}
|
|
|
|
// CalculateVideoSellDays 计算审核通过后天数
|
|
func CalculateVideoSellDays(reviewdAt time.Time) float64 {
|
|
if reviewdAt.IsZero() {
|
|
return 0
|
|
}
|
|
return math.Round(time.Since(reviewdAt).Hours() / 24)
|
|
}
|
|
|
|
// CalculatePurchaseRate 计算视频购买率
|
|
func CalculatePurchaseRate(sellCount, playCount int64) float64 {
|
|
if playCount <= 0 {
|
|
return 0.00
|
|
}
|
|
value, _ := strconv.ParseFloat(decimal.NewFromInt(sellCount).Div(decimal.NewFromInt(playCount)).Mul(decimal.NewFromInt(100)).StringFixed(2), 64)
|
|
return value
|
|
}
|
|
|
|
// CalculateClickRate 计算视频点击率
|
|
func CalculateClickRate(pageViewCount, playCount int64) float64 {
|
|
if playCount <= 0 {
|
|
return 0.00
|
|
}
|
|
value, _ := strconv.ParseFloat(decimal.NewFromInt(pageViewCount).Div(decimal.NewFromInt(playCount)).Mul(decimal.NewFromInt(100)).StringFixed(2), 64)
|
|
return value
|
|
}
|
|
|
|
// CalculateLikeRate 计算视频点赞率
|
|
func CalculateLikeRate(likeCount, playCount int64) float64 {
|
|
if playCount <= 0 {
|
|
return 0.00
|
|
}
|
|
value, _ := strconv.ParseFloat(decimal.NewFromInt(likeCount).Div(decimal.NewFromInt(playCount)).Mul(decimal.NewFromInt(100)).StringFixed(2), 64)
|
|
return value
|
|
}
|