@@ -0,0 +1,89 @@
|
||||
package vidhelp
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"91porn-server/common/constant/redisconst"
|
||||
"91porn-server/common/log"
|
||||
"91porn-server/models/v/vidmod"
|
||||
"91porn-server/web/webg"
|
||||
|
||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||
)
|
||||
|
||||
func getVidKey(vids []primitive.ObjectID) []string {
|
||||
format := redisconst.VideoInfoKey()
|
||||
keys := make([]string, len(vids))
|
||||
for i, v := range vids {
|
||||
keys[i] = fmt.Sprintf(format, v.Hex())
|
||||
}
|
||||
return keys
|
||||
}
|
||||
|
||||
func parseVideoInfo(data []interface{}) []*vidmod.VideoModel {
|
||||
infos := make([]*vidmod.VideoModel, 0, len(data))
|
||||
for _, d := range data {
|
||||
str, ok := d.(string)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
var v vidmod.VideoModel
|
||||
if err := json.Unmarshal([]byte(str), &v); err != nil {
|
||||
continue
|
||||
}
|
||||
infos = append(infos, &v)
|
||||
}
|
||||
return infos
|
||||
}
|
||||
|
||||
func getVideoListByIDsFromRedis(ids []primitive.ObjectID) ([]*vidmod.VideoModel, error) {
|
||||
sInfo := getVidKey(ids)
|
||||
uInfo, err := webg.Redis.MGet(sInfo...)
|
||||
if err != nil {
|
||||
log.Error("getVideoListByIDsFromRedis error", log.Any("ids", ids), log.Any("sInfo", sInfo), log.E(err))
|
||||
return nil, err
|
||||
}
|
||||
videoInfo := parseVideoInfo(uInfo)
|
||||
return videoInfo, nil
|
||||
}
|
||||
|
||||
func setVideoListByIDs2Redis(infos []*vidmod.VideoModel) error {
|
||||
expire := redisconst.VideoInfoExpire()
|
||||
format := redisconst.VideoInfoKey()
|
||||
for _, v := range infos {
|
||||
d, err := json.Marshal(v)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
s := fmt.Sprintf(format, v.ID.Hex())
|
||||
_ = webg.Redis.Set(s, string(d), expire)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func incComment(vid primitive.ObjectID) {
|
||||
infos, err := getVideoListByIDsFromRedis([]primitive.ObjectID{vid})
|
||||
if err != nil || len(infos) == 0 {
|
||||
return
|
||||
}
|
||||
if infos[0] == nil {
|
||||
return
|
||||
}
|
||||
infos[0].CommentCount++
|
||||
infos[0].FakeCommentCount++
|
||||
_ = setVideoListByIDs2Redis(infos)
|
||||
}
|
||||
|
||||
func decComment(vid primitive.ObjectID) {
|
||||
infos, err := getVideoListByIDsFromRedis([]primitive.ObjectID{vid})
|
||||
if err != nil || len(infos) == 0 {
|
||||
return
|
||||
}
|
||||
if infos[0] == nil {
|
||||
return
|
||||
}
|
||||
infos[0].CommentCount--
|
||||
infos[0].FakeCommentCount--
|
||||
_ = setVideoListByIDs2Redis(infos)
|
||||
}
|
||||
@@ -0,0 +1,417 @@
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user