@@ -0,0 +1,409 @@
|
||||
package vidser
|
||||
|
||||
import (
|
||||
"91porn-server/app/appg"
|
||||
"91porn-server/app/service/vidhelpser"
|
||||
"91porn-server/common"
|
||||
"91porn-server/common/constant"
|
||||
"91porn-server/common/constant/redisconst"
|
||||
"91porn-server/common/elastic"
|
||||
"91porn-server/common/log"
|
||||
"91porn-server/models/commod"
|
||||
"91porn-server/models/v/mediamod"
|
||||
"91porn-server/models/v/mediatagmod"
|
||||
"91porn-server/models/v/tagmod"
|
||||
"91porn-server/models/v/vidmod"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/vmihailenco/msgpack/v5"
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||
"go.mongodb.org/mongo-driver/mongo/options"
|
||||
)
|
||||
|
||||
func NewsTypeToSting(in string) string {
|
||||
var libraryTypeName string
|
||||
switch in {
|
||||
case constant.SP:
|
||||
libraryTypeName = "影片"
|
||||
case constant.SHORT:
|
||||
libraryTypeName = "抖音"
|
||||
case constant.Cartoon:
|
||||
libraryTypeName = "动漫"
|
||||
case constant.Comics:
|
||||
libraryTypeName = "漫画"
|
||||
case constant.PIC:
|
||||
libraryTypeName = "图集"
|
||||
case constant.COVER:
|
||||
libraryTypeName = "帖子"
|
||||
}
|
||||
return libraryTypeName
|
||||
}
|
||||
|
||||
// GetLibrary 获取片库详情
|
||||
func GetLibrary(uid uint64) (res vidmod.LibraryData, err error) {
|
||||
var data vidmod.LibraryData
|
||||
|
||||
// 获取缓存
|
||||
str, err := appg.Redis.Get(redisconst.VideoLibraryCache)
|
||||
if err != nil {
|
||||
log.Warn(fmt.Sprintf("uid:%v;缓存获取片库信息异常:%v", uid, err))
|
||||
}
|
||||
if str != nil {
|
||||
if err = msgpack.Unmarshal([]byte(*str), &data); err == nil {
|
||||
return data, nil
|
||||
}
|
||||
log.Warn(fmt.Sprintf("uid:%v;解析片库缓存数据异常:%v", uid, err))
|
||||
}
|
||||
data.OrderBy = append(data.OrderBy, vidmod.SortKey{
|
||||
Key: "new",
|
||||
Name: "最新上架",
|
||||
}, vidmod.SortKey{
|
||||
Key: "playNum",
|
||||
Name: "最多观看",
|
||||
}, vidmod.SortKey{
|
||||
Key: "love",
|
||||
Name: "最多收藏",
|
||||
})
|
||||
|
||||
data.Canvas = append(data.Canvas, vidmod.SortKey{
|
||||
Key: constant.SP,
|
||||
Name: NewsTypeToSting(constant.SP),
|
||||
}, vidmod.SortKey{
|
||||
Key: constant.SHORT,
|
||||
Name: NewsTypeToSting(constant.SHORT),
|
||||
}, vidmod.SortKey{
|
||||
Key: constant.Cartoon,
|
||||
Name: NewsTypeToSting(constant.Cartoon),
|
||||
}, vidmod.SortKey{
|
||||
Key: constant.Comics,
|
||||
Name: NewsTypeToSting(constant.Comics),
|
||||
}, vidmod.SortKey{
|
||||
Key: constant.PIC,
|
||||
Name: NewsTypeToSting(constant.PIC),
|
||||
}, vidmod.SortKey{
|
||||
Key: constant.COVER,
|
||||
Name: NewsTypeToSting(constant.COVER),
|
||||
})
|
||||
|
||||
data.PaymentType = append(data.PaymentType, vidmod.SortKey{
|
||||
Key: "",
|
||||
Name: "全部",
|
||||
}, vidmod.SortKey{
|
||||
Key: "vip",
|
||||
Name: "VIP",
|
||||
}, vidmod.SortKey{
|
||||
Key: "point",
|
||||
Name: "金币",
|
||||
})
|
||||
|
||||
data.TimeType = append(
|
||||
data.TimeType, vidmod.SortKey{
|
||||
Key: "1",
|
||||
Name: "本月",
|
||||
}, vidmod.SortKey{
|
||||
Key: "2",
|
||||
Name: "三个月内",
|
||||
}, vidmod.SortKey{
|
||||
Key: "3",
|
||||
Name: "半年内",
|
||||
}, vidmod.SortKey{
|
||||
Key: "4",
|
||||
Name: "更久",
|
||||
})
|
||||
|
||||
data.VidTags = append(data.VidTags, vidmod.Tag{
|
||||
ID: "",
|
||||
Name: "全部类型",
|
||||
})
|
||||
data.ACGTags = append(data.ACGTags, vidmod.Tag{
|
||||
ID: "",
|
||||
Name: "全部类型",
|
||||
})
|
||||
|
||||
wg := sync.WaitGroup{}
|
||||
wg.Add(2)
|
||||
common.Go(func() {
|
||||
defer wg.Done()
|
||||
// 获取最热标签
|
||||
tags, _, err := tagmod.GetLibraryTagList(commod.Page{PageNumber: 1, PageSize: 20})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if len(tags) > 0 {
|
||||
for _, t := range tags {
|
||||
data.VidTags = append(data.VidTags, vidmod.Tag{
|
||||
ID: t.ID.Hex(),
|
||||
Name: t.TagName,
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
common.Go(func() {
|
||||
defer wg.Done()
|
||||
// 获取ACG所有推荐标签
|
||||
tagFilter := bson.M{"active": true, "isDelete": false, "isDiscovery": true}
|
||||
tagOp := options.Find().SetLimit(20).SetSort(bson.D{{Key: "sort", Value: -1}})
|
||||
mediaTags, err := mediatagmod.QueryAllList(tagFilter, tagOp)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if len(mediaTags) > 0 {
|
||||
for _, t := range mediaTags {
|
||||
data.ACGTags = append(data.ACGTags, vidmod.Tag{
|
||||
ID: t.ID.Hex(),
|
||||
Name: t.Name,
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
wg.Wait()
|
||||
|
||||
common.Go(func() {
|
||||
// 加入缓存 随机1-3分钟缓存
|
||||
random := rand.Intn(120) + 60
|
||||
d, err := msgpack.Marshal(data)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if err = appg.Redis.Set(redisconst.VideoLibraryCache, d, time.Duration(random)*time.Second); err != nil {
|
||||
log.Warn(fmt.Sprintf("uid:%v, 保存缓存数据异常:%v", uid, err))
|
||||
}
|
||||
})
|
||||
return data, nil
|
||||
}
|
||||
|
||||
type LibraryElasticSearchRequest struct {
|
||||
Keyword LibraryReq `json:"keyword" bson:"keyword" binding:"required"` // 关键词
|
||||
UID uint64 `json:"-"` // 用户ID
|
||||
commod.Page
|
||||
}
|
||||
|
||||
type LibraryElasticSearchResponse struct {
|
||||
List []vidmod.ESVideo `json:"list"` // list
|
||||
HasNext bool `json:"hasNext"` // hasNext
|
||||
Total int `json:"total"` // total
|
||||
}
|
||||
|
||||
type LibraryReq struct {
|
||||
Canvas SortKey `json:"canvas" bson:"canvas"` // 视频分类
|
||||
OrderBy SortKey `json:"orderBy" bson:"orderBy"` // 视频排序
|
||||
Tags SearchTag `json:"tags" bson:"tags"` // 全部标签
|
||||
PaymentType SortKey `json:"paymentType" bson:"paymentType"` // 付费分类
|
||||
TimeType SortKey `json:"timeType" bson:"timeType"` // 时间排序
|
||||
}
|
||||
|
||||
type LibraryData struct {
|
||||
Canvas []SortKey `json:"canvas" bson:"canvas"` // 视频分类
|
||||
OrderBy []SortKey `json:"orderBy" bson:"orderBy"` // 视频排序
|
||||
VidTags []SearchTag `json:"vidTags" bson:"vidTags"` // 全部视频标签
|
||||
ACGTags []SearchTag `json:"acgTags" bson:"acgTags"` // 全部ACG标签
|
||||
PaymentType []SortKey `json:"paymentType" bson:"paymentType"` // 付费分类
|
||||
TimeType []SortKey `json:"timeType" bson:"timeType"` // 时间排序
|
||||
}
|
||||
|
||||
type SortKey struct {
|
||||
Key string `json:"key" bson:"key"` // 健值
|
||||
Name string `json:"name" bson:"name"` // 健名称
|
||||
}
|
||||
|
||||
type SearchTag struct {
|
||||
ID string `json:"id" bson:"id"` // 标签ID
|
||||
Name string `json:"name" bson:"name"` // 标签名称
|
||||
}
|
||||
|
||||
type AppElasticSearchLibraryResponse struct {
|
||||
List []*vidmod.VideoInfoResp `json:"list" bson:"list"` // 视频列表
|
||||
AllMediaList []*mediamod.AppMediaBase `json:"allMediaList" bson:"allMediaList"` // ACG列表
|
||||
HasNext bool `json:"hasNext" bson:"hasNext"` // 是否下一页
|
||||
Total int `json:"total" bson:"total"` // 总数
|
||||
}
|
||||
|
||||
func (in *LibraryElasticSearchRequest) CheckSearchType() (AppElasticSearchLibraryResponse, error) {
|
||||
var (
|
||||
data AppElasticSearchLibraryResponse
|
||||
err error
|
||||
)
|
||||
|
||||
switch in.Keyword.Canvas.Key {
|
||||
case constant.SP, constant.SHORT, constant.PIC, constant.COVER:
|
||||
data, err = in.VidLibrarySearch()
|
||||
case constant.Cartoon, constant.Comics:
|
||||
data, err = in.MediaLibrarySearch()
|
||||
}
|
||||
if err != nil {
|
||||
return data, err
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
|
||||
func (in *LibraryElasticSearchRequest) VidLibrarySearch() (AppElasticSearchLibraryResponse, error) {
|
||||
resp := AppElasticSearchLibraryResponse{}
|
||||
from := in.Skip64()
|
||||
size := in.Limit64()
|
||||
|
||||
must := elastic.A{
|
||||
{"term": elastic.M{"newsType.keyword": in.Keyword.Canvas.Key}},
|
||||
}
|
||||
if in.Keyword.Tags.ID != "" {
|
||||
tag := elastic.M{"term": elastic.M{"tags.keyword": in.Keyword.Tags.ID}}
|
||||
must = append(must, tag)
|
||||
}
|
||||
timeType := HandleTimeType(in.Keyword.TimeType.Key)
|
||||
must = append(must, timeType...)
|
||||
|
||||
payType := HandlePayType(in.Keyword.PaymentType.Key)
|
||||
must = append(must, payType...)
|
||||
short := HandleShort(in.Keyword.OrderBy.Key)
|
||||
// 根据数据结构组装数据
|
||||
query := elastic.M{
|
||||
"query": elastic.M{
|
||||
"bool": elastic.M{
|
||||
"must": must,
|
||||
},
|
||||
},
|
||||
"sort": short,
|
||||
"from": from,
|
||||
"size": size + 1,
|
||||
}
|
||||
|
||||
res, err := vidmod.SearchByCondWithTotal(query)
|
||||
if err != nil {
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
hasNext := false
|
||||
videosIDs := make([]primitive.ObjectID, 0)
|
||||
for _, v := range res.Hits {
|
||||
videosIDs = append(videosIDs, v.Source.ID)
|
||||
}
|
||||
|
||||
if len(videosIDs) > int(size) {
|
||||
hasNext = true
|
||||
videosIDs = videosIDs[:size]
|
||||
}
|
||||
|
||||
vidMods, err := vidmod.GetVideoListByIDs(videosIDs)
|
||||
if err != nil {
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
var (
|
||||
sortVidModels = make([]*vidmod.VideoModel, 0)
|
||||
vidMap = make(map[primitive.ObjectID]*vidmod.VideoModel)
|
||||
)
|
||||
for _, videoModel := range vidMods {
|
||||
vidMap[videoModel.ID] = videoModel
|
||||
}
|
||||
for _, vid := range videosIDs {
|
||||
if v, ok := vidMap[vid]; ok {
|
||||
sortVidModels = append(sortVidModels, v)
|
||||
}
|
||||
}
|
||||
data := vidhelpser.NewEncodeVideoInfoNotStatusForSearch(in.UID, sortVidModels)
|
||||
|
||||
resp.List = data
|
||||
resp.HasNext = hasNext
|
||||
resp.Total = res.Total.Value
|
||||
|
||||
// 查询结果数量出现不一致,说名有的帖子不存在了,需要删除
|
||||
if len(videosIDs) > 0 && len(videosIDs) != len(vidMods) {
|
||||
common.Go(func() {
|
||||
HandleDiffVideo(vidMap, videosIDs)
|
||||
})
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func HandleDiffVideo(vidMods map[primitive.ObjectID]*vidmod.VideoModel, videosIDs []primitive.ObjectID) {
|
||||
var source = elastic.M{}
|
||||
var diffVid []string
|
||||
for _, vid := range videosIDs {
|
||||
if _, ok := vidMods[vid]; !ok {
|
||||
source[vid.Hex()] = vid.Hex()
|
||||
diffVid = append(diffVid, vid.Hex())
|
||||
}
|
||||
}
|
||||
if len(source) > 0 {
|
||||
log.Info(fmt.Sprintf("search delete videosIDs:%v", diffVid))
|
||||
if err := vidmod.DeleteByCond(source); err != nil {
|
||||
log.Info(fmt.Sprintf("Elastic del data failed, err:%v", err))
|
||||
return
|
||||
}
|
||||
log.Info(fmt.Sprintf("Elastic del data succsss, count:%v", len(source)))
|
||||
}
|
||||
}
|
||||
|
||||
func HandleTimeType(key string) elastic.A {
|
||||
var timeTypeValue = elastic.A{}
|
||||
now := time.Now()
|
||||
switch key {
|
||||
case "1": // 本月
|
||||
timeTypeValue = append(timeTypeValue,
|
||||
elastic.M{"range": elastic.M{"reviewAt": elastic.M{"gt": now.AddDate(0, -1, 0)}}},
|
||||
)
|
||||
case "2": // 3月内
|
||||
timeTypeValue = append(timeTypeValue,
|
||||
elastic.M{"range": elastic.M{"reviewAt": elastic.M{"gt": now.AddDate(0, -3, 0), "lt": now.AddDate(0, -1, 0)}}},
|
||||
)
|
||||
case "3": // 半年内
|
||||
timeTypeValue = append(timeTypeValue,
|
||||
elastic.M{"range": elastic.M{"reviewAt": elastic.M{"gt": now.AddDate(0, -6, 0), "lt": now.AddDate(0, -3, 0)}}},
|
||||
)
|
||||
case "4": // 更久
|
||||
timeTypeValue = append(timeTypeValue,
|
||||
elastic.M{"range": elastic.M{"reviewAt": elastic.M{"gt": now.AddDate(-5, 0, 0), "lt": now.AddDate(0, -6, 0)}}},
|
||||
)
|
||||
default:
|
||||
timeTypeValue = append(timeTypeValue,
|
||||
elastic.M{"range": elastic.M{"reviewAt": elastic.M{"gt": now.AddDate(-3, -2, 0)}}},
|
||||
)
|
||||
}
|
||||
return timeTypeValue
|
||||
}
|
||||
|
||||
func HandlePayType(key string) elastic.A {
|
||||
var payTypeValue = elastic.A{}
|
||||
switch key {
|
||||
case "free":
|
||||
payTypeValue = append(payTypeValue,
|
||||
elastic.M{"term": elastic.M{"status": 3}},
|
||||
elastic.M{"term": elastic.M{"coins": 0}},
|
||||
)
|
||||
case "vip":
|
||||
payTypeValue = append(payTypeValue,
|
||||
elastic.M{"term": elastic.M{"status": 1}},
|
||||
elastic.M{"term": elastic.M{"coins": 0}},
|
||||
)
|
||||
case "point":
|
||||
payTypeValue = append(payTypeValue,
|
||||
elastic.M{"terms": elastic.M{"status": []int{1, 3}}},
|
||||
elastic.M{"range": elastic.M{"coins": elastic.M{"gt": 0}}},
|
||||
)
|
||||
default:
|
||||
payTypeValue = append(payTypeValue, elastic.M{"terms": elastic.M{"status": []int{1, 3}}})
|
||||
}
|
||||
return payTypeValue
|
||||
}
|
||||
|
||||
func HandleShort(key string) elastic.A {
|
||||
var payTypeValue elastic.A
|
||||
switch key {
|
||||
case "playNum":
|
||||
payTypeValue = elastic.A{{"playCount": elastic.M{"order": "desc"}}}
|
||||
case "love":
|
||||
payTypeValue = elastic.A{{"collectCount": elastic.M{"order": "desc"}}}
|
||||
case "new":
|
||||
payTypeValue = elastic.A{{"reviewAt": elastic.M{"order": "desc"}}}
|
||||
default:
|
||||
payTypeValue = elastic.A{{"fakeLikeCount": elastic.M{"order": "desc"}}, {"reviewAt": elastic.M{"order": "desc"}}}
|
||||
}
|
||||
return payTypeValue
|
||||
}
|
||||
Reference in New Issue
Block a user