package playlgmod import ( "fmt" "math" "time" "91porn-server/common/db" "91porn-server/common/log" "91porn-server/models" "github.com/jinzhu/now" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" ) const table = models.PlayLog const maxReadVideos = 200 // initIndex 初始化索引 func initIndex() { many := []mongo.IndexModel{ { Keys: bson.D{{Key: "uid", Value: 1}}, }, { Keys: bson.D{{Key: "videoID", Value: 1}}, }, { Keys: bson.D{{Key: "createdAt", Value: -1}}, }, } if _, err := coll(nil).CreateIndex(many); err != nil { panic(fmt.Sprintf("%s model set index err ==>[%+v]", table, err)) } } func coll(t *db.MongoTool) *db.MongoTool { if t == nil { return mdb.Coll(table) } return t.Coll(table) } // InsertPlayRecord 记录一个播放行为 func InsertPlayRecord(p PlayLog) error { if _, err := coll(nil).InsertOne(&p); err != nil { log.Error("InsertPlayRecord error", log.Any("p", p), log.E(err)) return err } return nil } // HasWatchedVideo 已经观看的视频 func HasWatchedVideo(uid uint64) ([]primitive.ObjectID, error) { now := time.Now() begin := now.AddDate(0, 0, -7) var logs []*PlayLog opts := options.FindOptions{} opts.SetSort(bson.D{{Key: "createdAt", Value: -1}}).SetLimit(maxReadVideos) if err := coll(nil).Find(&logs, bson.M{"uid": uid, "createdAt": bson.M{"$gt": begin}}, &opts); err != nil { log.Error("HasWatchedVideo error", log.Any("uid", uid), log.E(err)) return nil, err } vids := make([]primitive.ObjectID, len(logs)) for i, l := range logs { vids[i] = l.VideoID } return vids, nil } // HasWatchedVideoCnt 已经观看的视频数 func HasWatchedVideoCnt(uids []uint64) ([]UIDCount, error) { now := time.Now() begin := now.AddDate(0, 0, -4) var datas []UIDCount cond := bson.M{"uid": bson.M{"$in": uids}, "createdAt": bson.M{"$gt": begin}} if err := coll(nil).Aggregate(&datas, []bson.M{ bson.M{"$match": cond}, bson.M{"$group": bson.M{"_id": "$uid", "count": bson.M{"$sum": 1}}}, }); err != nil { log.Error("HasWatchedVideoCnt error", log.Any("uids", uids), log.E(err)) } return datas, nil } // HasWatchedTags 当天已经观看过的标签id func HasWatchedTags(uid uint64, top int) ([]string, error) { tagIDs := []string{} var data []TagIDCount if err := coll(nil).Aggregate(&data, []bson.M{ bson.M{"$match": bson.M{"uid": uid, "tagID": bson.M{"$exists": true}, "createdAt": bson.M{"$gte": now.BeginningOfDay()}}}, bson.M{"$group": bson.M{"_id": "$tagID", "count": bson.M{"$sum": 1}}}, bson.M{"$sort": bson.D{{Key: "count", Value: -1}}}, bson.M{"$limit": top}, }); err != nil { log.Error("HasWatchedTags error", log.Any("uid", uid), log.Any("top", top), log.E(err)) return tagIDs, err } tagIDs = make([]string, len(data)) for i, d := range data { tagIDs[i] = d.TagID.Hex() } return tagIDs, nil } // getPlayRecordSkipSize 计算跳转 func getPlayRecordSkipSize(page, size uint64, cond bson.M) (uint64, uint64, uint64, error) { var total uint64 = 10000 totalpages := uint64(math.Ceil(float64(total) / float64(size))) if page > totalpages { page = totalpages } if page < 1 { page = 1 } return (page - 1) * size, totalpages, total, nil } // GetPlayRecordList 获取播放记录 func getPlayRecordList(page, size uint64, cond bson.M, sort bson.D) ([]*PlayLog, uint64, uint64, error) { skip, totalPages, total, err := getPlayRecordSkipSize(page, size, cond) if err != nil { return nil, 0, 0, err } opts := options.FindOptions{} if sort != nil { opts.SetSort(sort) } opts.SetSkip(int64(skip)).SetLimit(int64(size)) var back []*PlayLog if err = coll(nil).Find(&back, cond, &opts); err != nil { log.Error("GetPlayRecordList error", log.Any("page", page), log.Any("size", size), log.Any("cond", cond), log.Any("sort", sort), log.E(err)) return nil, totalPages, total, err } return back, totalPages, total, nil } // GetNearPlayLog 获取用户最近的观影记录 func GetNearPlayLog(uid uint64) error { var p PlayLog opts := options.FindOne().SetSort(bson.D{{Key: "createdAt", Value: -1}}) return coll(nil).FindOne(&p, bson.M{"uid": uid}, opts) } // GetViewLogToday 当天是否看过此视频 func GetViewLogToday(uid uint64, vid primitive.ObjectID) bool { cond := bson.M{"uid": uid, "videoID": vid, "createdAt": bson.M{"$gte": now.BeginningOfDay(), "$lte": now.EndOfDay()}} cnt, _ := coll(nil).Count(cond) return cnt > 0 } // 当天是否观看过视频 func IsViewToday(uid uint64) bool { cond := bson.M{"uid": uid, "createdAt": bson.M{"$gte": now.BeginningOfDay(), "$lte": now.EndOfDay()}} cnt, _ := coll(nil).Count(cond) return cnt > 0 } // PlayCountMapByTime PlayCountMapByTime playWays 0免费 1付费 2.试看 func PlayCountMapByTime(start time.Time, end time.Time, playWays []int) (map[primitive.ObjectID]int64, error) { if len(playWays) == 0 { return make(map[primitive.ObjectID]int64), nil } filter := bson.M{ "createdAt": bson.M{ "$gte": start, "$lt": end, }, "playWay": bson.M{"$in": playWays}, //0免费 1付费 2.试看 } pipeline := []bson.M{ { "$match": filter, }, { "$group": bson.M{ "_id": "$videoID", "count": bson.M{ "$sum": 1, }, }, }, } list := make([]struct { VID primitive.ObjectID `bson:"_id"` Count int64 `bson:"count"` }, 0) if err := coll(nil).Aggregate(&list, pipeline); err != nil { return nil, fmt.Errorf("PlayLog PlayCountMapByTime err: %s", err.Error()) } ret := make(map[primitive.ObjectID]int64) for _, v := range list { ret[v.VID] = v.Count } return ret, nil } func GetPayUserCount(vid []primitive.ObjectID) (int64, error) { if len(vid) == 0 { return 0, nil } pipeline := []bson.M{ { "$match": bson.M{ "videoID": bson.M{ "$in": vid, }, }, }, { "$group": bson.M{ "_id": "$uid", }, }, } count, err := coll(nil).Count(pipeline) if err != nil { return 0, fmt.Errorf("GetPatUserCount err: %s", err.Error()) } return count, nil } // PlayUIDListByTime // playWay 0,免费 1付费 2.试看 ,nil All func PlayUIDListByTime(start time.Time, end time.Time, playWay *int) ([]uint64, error) { match := bson.M{ "$match": bson.M{ "createdAt": bson.M{ "$gte": start, "$lt": end, }, }, } if playWay != nil { match["playWay"] = *playWay //0,免费 1付费 2.试看 } pipeline := []bson.M{match} pipeline = append(pipeline, bson.M{ "$group": bson.M{ "_id": "$uid", }, }) list := []struct { UID uint64 `bson:"_id"` }{} if err := coll(nil).Aggregate(&list, pipeline); err != nil { return nil, fmt.Errorf("PlayUIDListByTime err: %s", err.Error()) } uidList := make([]uint64, len(list)) for i, v := range list { uidList[i] = v.UID } return uidList, nil } func backWatchParam(param WatchReq) map[string]interface{} { m := make(map[string]interface{}) if param.UID > 0 { m["uid"] = param.UID } if param.PlayWay == 1 { m["playWay"] = 0 } if param.PlayWay == 2 { m["playWay"] = 1 } if param.PlayWay == 3 { m["playWay"] = 2 } if !param.End.IsZero() { i := make(map[string]time.Time) i["$gte"] = param.Start i["$lt"] = param.End m["createdAt"] = i } return m } // GetPlayLog 获取播放日志 func GetPlayLog(param WatchReq) ([]*PlayLog, uint64, error) { cond := backWatchParam(param) sort := bson.D{{Key: "createdAt", Value: -1}} infos, _, total, err := getPlayRecordList(param.PageNumber, param.PageSize, bson.M(cond), sort) return infos, total, err } // GetUIDPlaySecondMap 用户播放时长(秒)map func GetUIDPlaySecondMap(uidList []uint64) (map[uint64]int64, error) { pipeline := []bson.M{ { "$match": bson.M{ "uid": bson.M{ "$in": uidList, }, }, }, { "$group": bson.M{ "_id": "$uid", "playSecond": bson.M{ "$sum": "$longer", }, }, }, } list := []struct { UID uint64 `bson:"_id"` PlaySecond int64 `bson:"playSecond"` }{} if err := coll(nil).Aggregate(&list, pipeline); err != nil { return nil, fmt.Errorf("GetUIDPlayTimeMap err: %s", err.Error()) } playSecondMap := make(map[uint64]int64, len(list)) for _, v := range list { playSecondMap[v.UID] = v.PlaySecond } return playSecondMap, nil } // 根据时间范围获取标签下的视频的播放次数 func GetTagPlayByTimeRange(start time.Time, end time.Time) ([]TagPlayCount, error) { list := make([]TagPlayCount, 0) pipeline := []bson.M{ { "$match": bson.M{ "tagID": bson.M{"$exists": true}, "createdAt": bson.M{"$gte": start, "$lt": end}, }, }, { "$group": bson.M{ "_id": bson.M{"videoID": "$videoID", "tagID": "$tagID"}, "playCount": bson.M{"$sum": 1}, }, }, } if err := coll(nil).Aggregate(&list, pipeline); err != nil { log.Error("models log play log model GetTagPlayByTimeRange error", log.E(err), log.Any("start", start), log.Any("end", end)) return nil, err } return list, nil } // 获取播放量最多的视频 func GetHotVid(start time.Time, end time.Time) ([]TagPlayCount, error) { list := make([]TagPlayCount, 0) pipeline := []bson.M{ { "$match": bson.M{ "tagID": bson.M{"$exists": true}, "createdAt": bson.M{"$gte": start, "$lt": end}, }, }, { "$group": bson.M{ "_id": bson.M{"videoID": "$videoID", "tagID": "$tagID"}, "playCount": bson.M{"$sum": 1}, }, }, } if err := coll(nil).Aggregate(&list, pipeline); err != nil { log.Error("models log play log model GetTagPlayByTimeRange error", log.E(err), log.Any("start", start), log.Any("end", end)) return nil, err } return list, nil } // 获取播放量最多的视频 func GetHotVidIDs() ([]VidCount, error) { list := make([]VidCount, 0) pipeline := []bson.M{ { "$match": bson.M{ "createdAt": bson.M{ "$gte": time.Now().AddDate(0, 0, -1), }, }, }, { "$group": bson.M{ "_id": "$videoID", "count": bson.M{"$sum": 1}, }, }, {"$sort": bson.M{ "count": -1, }}, { "$limit": 20, }, } return list, coll(nil).Aggregate(&list, pipeline) } // 获取播放量最多的视频 func GetHotPublishesr() ([]PublisherCount, error) { list := make([]PublisherCount, 0) pipeline := []bson.M{ { "$group": bson.M{ "_id": "$publisher", "count": bson.M{"$sum": 1}, }, }, {"$match": bson.M{ "_id": bson.M{"$gt": 0}, }}, {"$sort": bson.M{ "count": -1, }}, { "$limit": 20, }, } return list, coll(nil).Aggregate(&list, pipeline) } func DeleteBeforeCreatedAt(t *db.MongoTool, tm time.Time) error { _, err := coll(t).DeleteMany(bson.M{"createdAt": bson.M{"$lt": tm}}) return err }