package models import ( "context" "fmt" "time" "videoweb/pub/common/log" "videoweb/pub/common/srvdef" "videoweb/pub/models/actress" "videoweb/pub/models/announcementmod" "videoweb/pub/models/cfg" "videoweb/pub/models/commentlikemod" "videoweb/pub/models/commentmod" "videoweb/pub/models/contactusmod" "videoweb/pub/models/contenttagmod" "videoweb/pub/models/detailnavmod" "videoweb/pub/models/esmod" "videoweb/pub/models/eventmod" "videoweb/pub/models/homebannermod" "videoweb/pub/models/hotnavmod" "videoweb/pub/models/ipblackmod" "videoweb/pub/models/ipdailystatmod" "videoweb/pub/models/m3u8requestlogmod" "videoweb/pub/models/mwacc" "videoweb/pub/models/oplog" "videoweb/pub/models/playletbackflowstatmod" "videoweb/pub/models/playletcategorymod" "videoweb/pub/models/playletchaptermod" "videoweb/pub/models/playletfavoritemod" "videoweb/pub/models/playlethomeconfigmod" "videoweb/pub/models/playletlikemod" "videoweb/pub/models/playletmod" "videoweb/pub/models/playlettagmod" "videoweb/pub/models/playletthememod" "videoweb/pub/models/questionnairemod" "videoweb/pub/models/richtextcontentmod" "videoweb/pub/models/seopushmod" "videoweb/pub/models/syncfilemod" "videoweb/pub/models/translationcategorymod" "videoweb/pub/models/translationmod" "videoweb/pub/models/userlogin" "videoweb/pub/models/usermod" "videoweb/pub/models/videocategorymod" "videoweb/pub/models/videocollectionmediamod" "videoweb/pub/models/videocreatermod" "videoweb/pub/models/videofavoritemod" "videoweb/pub/mongos" "videoweb/pub/models/videoinformationmod" "videoweb/pub/models/videolikemod" "videoweb/pub/models/videotagmod" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" ) func Init() { log.Info("models init start..") ctx := context.Background() cfg.Init(ctx) mwacc.Init(ctx) oplog.Init(ctx) m3u8requestlogmod.Init(ctx) videocategorymod.Init(ctx) videoinformationmod.Init(ctx) videofavoritemod.Init(ctx) videolikemod.Init(ctx) videotagmod.Init(ctx) translationcategorymod.Init(ctx) translationmod.Init(ctx) contenttagmod.Init(ctx) playletcategorymod.Init(ctx) playlethomeconfigmod.Init(ctx) playlettagmod.Init(ctx) playletthememod.Init(ctx) playletmod.Init(ctx) playletbackflowstatmod.Init(ctx) playletchaptermod.Init(ctx) playletlikemod.Init(ctx) playletfavoritemod.Init(ctx) initWatchHistory(ctx) videocategorymod.Init(ctx) videocreatermod.Init(ctx) videotagmod.Init(ctx) videoinformationmod.Init(ctx) videocreatermod.Init(ctx) syncfilemod.Init(ctx) seopushmod.Init(ctx) richtextcontentmod.Init(ctx) announcementmod.Init(ctx) commentmod.Init(ctx) commentlikemod.Init(ctx) videocollectionmediamod.Init(ctx) ipblackmod.Init(ctx) esmod.Init(ctx) actress.Init(ctx) contactusmod.Init(ctx) detailnavmod.Init(ctx) hotnavmod.Init(ctx) homebannermod.Init(ctx) eventmod.Init(ctx) usermod.Init(ctx) userlogin.Init(ctx) questionnairemod.Init(ctx) ipdailystatmod.Init(ctx) log.Info("models init end") } const ( WatchHistoryTypePlaylet int64 = 1 WatchHistoryTypeVideo int64 = 2 WatchHistoryRetentionDays = 60 watchHistoryCollectionName = "watch_history" WatchHistoryCollectionName = watchHistoryCollectionName WatchHistoryUserID = "userId" WatchHistoryDataType = "dataType" WatchHistoryContentID = "contentId" WatchHistoryChapterID = "chapterId" WatchHistoryEpisode = "episode" WatchHistoryCreatedAt = "createdAt" WatchHistoryUpdatedAt = "updatedAt" ) // WatchHistory 保存当前用户最近观看的内容 type WatchHistory struct { UserID int64 `bson:"userId"` DataType int64 `bson:"dataType"` ContentID int64 `bson:"contentId"` ChapterID int64 `bson:"chapterId"` Episode int64 `bson:"episode"` CreatedAt time.Time `bson:"createdAt"` UpdatedAt time.Time `bson:"updatedAt"` } var watchHistoryColl *mongos.Collection // initWatchHistory 初始化观看历史及 60 天 TTL 索引 func initWatchHistory(ctx context.Context) { watchHistoryColl = mongos.Shop.Coll(watchHistoryCollectionName) indexes := []mongo.IndexModel{ {Keys: bson.D{{Key: WatchHistoryUserID, Value: 1}, {Key: WatchHistoryDataType, Value: 1}, {Key: WatchHistoryContentID, Value: 1}}, Options: options.Index().SetUnique(true)}, {Keys: bson.D{{Key: WatchHistoryUserID, Value: 1}, {Key: WatchHistoryDataType, Value: 1}, {Key: WatchHistoryUpdatedAt, Value: -1}, {Key: "_id", Value: -1}}}, {Keys: bson.D{{Key: WatchHistoryUpdatedAt, Value: 1}}, Options: options.Index().SetExpireAfterSeconds(WatchHistoryRetentionDays * 24 * 60 * 60)}, } if _, err := watchHistoryColl.CreateIndex(ctx, indexes); err != nil { panic(fmt.Sprintf("(models:initWatchHistory) Create Index failed! err:%+v:", err)) } } // TouchWatchHistory 从已验证的播放清单刷新历史 func TouchWatchHistory(ctx context.Context, item WatchHistory) *srvdef.SrvErr { filter := bson.M{WatchHistoryUserID: item.UserID, WatchHistoryDataType: item.DataType, WatchHistoryContentID: item.ContentID} if item.DataType == WatchHistoryTypePlaylet { sameChapter := bson.M{WatchHistoryUserID: item.UserID, WatchHistoryDataType: item.DataType, WatchHistoryContentID: item.ContentID, WatchHistoryChapterID: item.ChapterID} result, err := watchHistoryColl.UpdateOne(ctx, sameChapter, bson.M{"$set": bson.M{WatchHistoryUpdatedAt: item.UpdatedAt, WatchHistoryEpisode: item.Episode}}) if err != nil { log.Warn("TouchWatchHistory failed", log.Any("filter", sameChapter), log.E(err)) return srvdef.New(srvdef.ErrDbUpdateError, "", "") } if result.MatchedCount > 0 { return nil } } update := bson.M{ "$set": bson.M{WatchHistoryChapterID: item.ChapterID, WatchHistoryEpisode: item.Episode, WatchHistoryUpdatedAt: item.UpdatedAt}, "$setOnInsert": bson.M{WatchHistoryUserID: item.UserID, WatchHistoryDataType: item.DataType, WatchHistoryContentID: item.ContentID, WatchHistoryCreatedAt: item.CreatedAt}, } if _, err := watchHistoryColl.UpdateOne(ctx, filter, update, options.Update().SetUpsert(true)); err != nil { if mongo.IsDuplicateKeyError(err) { _, err = watchHistoryColl.UpdateOne(ctx, filter, bson.M{"$set": update["$set"]}) if err == nil { return nil } } log.Warn("TouchWatchHistory failed", log.Any("filter", filter), log.E(err)) return srvdef.New(srvdef.ErrDbUpdateError, "", "") } return nil } // AggregateWatchHistory 聚合查询观看历史 func AggregateWatchHistory(ctx context.Context, bind interface{}, pipeline []bson.M) *srvdef.SrvErr { if err := watchHistoryColl.Aggregate(ctx, bind, pipeline); err != nil { log.Warn("AggregateWatchHistory failed", log.Any("pipeline", pipeline), log.E(err)) return srvdef.New(srvdef.ErrDbQueryError, "", "") } return nil } // DeleteWatchHistory 删除当前用户指定类型的观看历史 func DeleteWatchHistory(ctx context.Context, userID, dataType int64) (int64, *srvdef.SrvErr) { filter := bson.M{WatchHistoryUserID: userID, WatchHistoryDataType: dataType} count, err := watchHistoryColl.DeleteMany(ctx, filter) if err != nil { log.Warn("DeleteWatchHistory failed", log.Any("filter", filter), log.E(err)) return 0, srvdef.New(srvdef.ErrDbDeleteError, "", "") } return count, nil }