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 }