1303 lines
39 KiB
Go
Executable File
1303 lines
39 KiB
Go
Executable File
package mediaser
|
|
|
|
import (
|
|
"91porn-server/app/appg"
|
|
"91porn-server/app/service/mediatagser"
|
|
"91porn-server/common"
|
|
"91porn-server/common/constant"
|
|
"91porn-server/common/constant/redisconst"
|
|
"91porn-server/common/elastic"
|
|
"91porn-server/common/log"
|
|
"91porn-server/common/timeutil"
|
|
topser "91porn-server/common/top"
|
|
topasist "91porn-server/common/top/asistant"
|
|
"91porn-server/common/top/dailytop"
|
|
"91porn-server/common/top/monthtop"
|
|
"91porn-server/common/top/weektop"
|
|
"91porn-server/models/cache/mediadata"
|
|
"91porn-server/models/cache/mediatagdata"
|
|
"91porn-server/models/commod"
|
|
"91porn-server/models/s/sectionstatmod"
|
|
"91porn-server/models/v/likemod"
|
|
"91porn-server/models/v/media_buy_record_mod"
|
|
"91porn-server/models/v/mediabookshelfmod"
|
|
"91porn-server/models/v/mediamod"
|
|
"91porn-server/models/v/mediatagdimensionmod"
|
|
"91porn-server/models/v/mediatagmod"
|
|
"91porn-server/models/v/modulesectionmod"
|
|
"fmt"
|
|
"github.com/golang-module/carbon/v2"
|
|
"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"
|
|
"strconv"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
type AppQueryListReq struct {
|
|
commod.Page
|
|
}
|
|
|
|
type AppListRes struct {
|
|
HasNext bool `json:"hasNext"`
|
|
List []*mediamod.AppMediaBase `json:"list"`
|
|
}
|
|
|
|
// GetList 获取列表
|
|
func (p *AppQueryListReq) GetList() AppListRes {
|
|
var res AppListRes
|
|
var err error
|
|
filter := bson.M{}
|
|
|
|
sort := bson.D{{"_id", -1}}
|
|
// 获取列表
|
|
var data []*mediamod.Media
|
|
data, res.HasNext, err = mediadata.GetListFromCache(filter, int64(p.Skip()), int64(p.Limit()), sort)
|
|
if err != nil {
|
|
return res
|
|
}
|
|
// 组装返回数据
|
|
for _, item := range data {
|
|
tmp := &mediamod.AppMediaBase{
|
|
ID: item.ID,
|
|
SortCode: item.SortCode,
|
|
Status: item.Status,
|
|
Title: item.Title,
|
|
Author: item.Anchor,
|
|
HorizontalCover: item.HorizontalCover,
|
|
VerticalCover: item.VerticalCover,
|
|
Tags: item.Tags,
|
|
Summary: item.Summary,
|
|
TotalEpisode: item.TotalEpisode,
|
|
MediaType: item.MediaType,
|
|
MediaSubType: item.MediaSubType,
|
|
Kind: item.Kind,
|
|
PermissionIconHide: item.PermissionIconHide,
|
|
Permission: item.Permission,
|
|
Price: item.Price,
|
|
Direction: item.Direction,
|
|
FreeTime: item.FreeTime,
|
|
CountComment: item.CountComment,
|
|
CountPurchases: item.CountPurchases,
|
|
CountBrowse: item.CountBrowse,
|
|
CountCollect: item.CountCollect,
|
|
CountLike: item.CountLike,
|
|
CountView: item.CountView,
|
|
Number: item.Number,
|
|
CreatedAt: item.CreatedAt,
|
|
UpdateTime: item.UpdateTime,
|
|
}
|
|
res.List = append(res.List, tmp)
|
|
}
|
|
|
|
return res
|
|
}
|
|
|
|
type AppQueryInfoReq struct {
|
|
ID string `json:"id" form:"id"` // id
|
|
}
|
|
|
|
// GetInfo 获取详情
|
|
func (p *AppQueryInfoReq) GetInfo(uid uint64) (resp *mediamod.AppMediaBase, err error) {
|
|
oid, err := primitive.ObjectIDFromHex(p.ID)
|
|
if err != nil {
|
|
return resp, err
|
|
}
|
|
|
|
var item mediamod.Media
|
|
item, err = mediadata.GetInfoFromCache(oid)
|
|
if err != nil {
|
|
log.Error("AppQueryInfoReq.GetInfo mediadata.GetInfoFromCache fail", log.Any("mediaId", p.ID), log.E(err))
|
|
return resp, err
|
|
}
|
|
if item.ID.IsZero() {
|
|
return resp, nil
|
|
}
|
|
if item.MediaType == mediamod.MediaTypeDrama && (item.Status != 1 || item.IsDelete) {
|
|
return nil, fmt.Errorf("drama is inactive")
|
|
}
|
|
res := FillMedias([]*mediamod.Media{&item}, uid, true)
|
|
resp = res[0]
|
|
// 累加浏览数
|
|
common.Go(func() {
|
|
// 增加父级的浏览数量
|
|
IncrCountBrowse(item.ID)
|
|
topasist.Incr(topser.TypeMedia(item.MediaType), item.ID.Hex(), 1)
|
|
})
|
|
return resp, nil
|
|
}
|
|
|
|
// GetUserStatus 获取 用户状态信息 只跟media这张表有关系
|
|
func GetUserStatus(uid uint64, mediaIds []primitive.ObjectID) map[primitive.ObjectID]mediamod.MediaStatus {
|
|
mPay := make(map[primitive.ObjectID]bool)
|
|
hasAddBookshelf := make(map[primitive.ObjectID]bool)
|
|
mLike := make(map[primitive.ObjectID]bool)
|
|
|
|
var wg sync.WaitGroup
|
|
wg.Add(3)
|
|
common.Go(func() {
|
|
defer wg.Done()
|
|
mPay, _ = media_buy_record_mod.IsWholeBuyBatch(uid, mediaIds)
|
|
})
|
|
common.Go(func() {
|
|
defer wg.Done()
|
|
mLike, _ = likemod.IsLikeByType(uid, []string{constant.LikeTypeText, constant.LikeTypeComics, constant.LikeTypeCartoon, constant.LikeTypeDrama}, mediaIds)
|
|
})
|
|
common.Go(func() {
|
|
defer wg.Done()
|
|
hasAddBookshelf, _ = mediabookshelfmod.HasAddBookshelf(uid, mediaIds)
|
|
})
|
|
wg.Wait()
|
|
m := map[primitive.ObjectID]mediamod.MediaStatus{}
|
|
for _, v := range mediaIds {
|
|
info := mediamod.MediaStatus{
|
|
HasPaid: mPay[v],
|
|
HasCollected: hasAddBookshelf[v],
|
|
HasLiked: mLike[v],
|
|
}
|
|
m[v] = info
|
|
}
|
|
return m
|
|
}
|
|
|
|
// GetLibrary 获取片库
|
|
func GetLibrary() (res []mediamod.AppLibrary, err error) {
|
|
var resp []mediamod.AppLibrary
|
|
|
|
str, err := appg.Redis.Get(redisconst.MediaLibraryInfo)
|
|
if err != nil {
|
|
log.Warn(fmt.Sprintf("缓存获取动漫片库信息异常:%v", err))
|
|
}
|
|
if str != nil {
|
|
if err = msgpack.Unmarshal([]byte(*str), &resp); err == nil {
|
|
return resp, nil
|
|
}
|
|
log.Warn(fmt.Sprintf("解析预售缓存数据异常:%v", err))
|
|
}
|
|
|
|
resp = append(resp, mediamod.AppLibrary{
|
|
Key: Video,
|
|
Name: "动漫",
|
|
}, mediamod.AppLibrary{
|
|
Key: Image,
|
|
Name: "漫画",
|
|
})
|
|
for i, d := range resp {
|
|
if d.Key == Video {
|
|
resp[i].Kind = append(resp[i].Kind, mediamod.KindInfo{
|
|
Key: "1",
|
|
Name: "哩番",
|
|
Cover: "cf230705/image/lm/34n/1la/2ck/7064ad102298311797d9f43b323a2ea4.png",
|
|
}, mediamod.KindInfo{
|
|
Key: "2",
|
|
Name: "3D",
|
|
Cover: "cf230705/image/18b/2zw/1dp/2wu/3b90ad609435c0037f7a8a90ed8e2de2.png",
|
|
}, mediamod.KindInfo{
|
|
Key: "3",
|
|
Name: "同人动画",
|
|
Cover: "cf230705/image/14q/5y/19x/p9/3c48b94311b361f2dcdb006200208751.png",
|
|
})
|
|
}
|
|
if d.Key == Image {
|
|
resp[i].Kind = append(resp[i].Kind, mediamod.KindInfo{
|
|
Key: "4",
|
|
Name: "单行本",
|
|
Cover: "cf230705/image/2a4/1kk/2hi/2xg/b830c4997f21ad4351ab0880fd2bc1be.png",
|
|
}, mediamod.KindInfo{
|
|
Key: "5",
|
|
Name: "连载漫画",
|
|
Cover: "cf230705/image/p2/1rq/2c3/nx/ce44dfc5406ef4d20cef04a683970f4c.png",
|
|
}, mediamod.KindInfo{
|
|
Key: "6",
|
|
Name: "韩漫",
|
|
Cover: "cf230705/image/1ol/26f/lb/2rq/872dab8f0ccd3c4eba6cba5171630112.png",
|
|
})
|
|
}
|
|
}
|
|
|
|
// 获取 动漫、漫画纬度
|
|
filter := bson.M{"status": 1, "isDelete": false}
|
|
op := options.Find().SetSort(bson.D{{"sortCode", -1}})
|
|
tagDimensions, err := mediatagdimensionmod.QueryAllList(filter, op)
|
|
if err != nil {
|
|
return resp, nil
|
|
}
|
|
|
|
if len(tagDimensions) > 0 {
|
|
for i, m := range resp {
|
|
for _, d := range tagDimensions {
|
|
if m.Key == "video" && d.Type == 1 {
|
|
for j := range resp[i].Kind {
|
|
resp[i].Kind[j].Dimension = append(resp[i].Kind[j].Dimension, mediamod.DimensionInfo{
|
|
Key: d.ID.Hex(),
|
|
Name: d.Name,
|
|
})
|
|
}
|
|
}
|
|
if m.Key == "image" && d.Type == 2 {
|
|
for j := range resp[i].Kind {
|
|
resp[i].Kind[j].Dimension = append(resp[i].Kind[j].Dimension, mediamod.DimensionInfo{
|
|
Key: d.ID.Hex(),
|
|
Name: d.Name,
|
|
})
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// 获取所有推荐标签
|
|
tagFilter := bson.M{"active": true, "isDelete": false, "isDiscovery": true}
|
|
tagOp := options.Find().SetSort(bson.D{{"sort", -1}})
|
|
mediaTags, err := mediatagmod.QueryAllList(tagFilter, tagOp)
|
|
if err != nil {
|
|
return resp, nil
|
|
}
|
|
|
|
if len(mediaTags) > 0 {
|
|
for i, m := range resp {
|
|
for _, t := range mediaTags {
|
|
if m.Key == "video" && t.Type == 1 && (t.Kind == 1 || t.Kind == 2 || t.Kind == 3) {
|
|
for j := range resp[i].Kind {
|
|
for d, k := range resp[i].Kind[j].Dimension {
|
|
kindStr := strconv.Itoa(t.Kind)
|
|
if t.Dimension == k.Name && resp[i].Kind[j].Key == kindStr {
|
|
resp[i].Kind[j].Dimension[d].Tag = append(resp[i].Kind[j].Dimension[d].Tag, mediamod.TagInfo{
|
|
ID: t.ID.Hex(),
|
|
Name: t.Name,
|
|
})
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if m.Key == "image" && t.Type == 2 && (t.Kind == 4 || t.Kind == 5 || t.Kind == 6) {
|
|
for j := range resp[i].Kind {
|
|
for d, k := range resp[i].Kind[j].Dimension {
|
|
kindStr := strconv.Itoa(t.Kind)
|
|
if t.Dimension == k.Name && resp[i].Kind[j].Key == kindStr {
|
|
resp[i].Kind[j].Dimension[d].Tag = append(resp[i].Kind[j].Dimension[d].Tag, mediamod.TagInfo{
|
|
ID: t.ID.Hex(),
|
|
Name: t.Name,
|
|
})
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
common.Go(func() {
|
|
bytes, _ := msgpack.Marshal(resp)
|
|
if err = appg.Redis.Set(redisconst.MediaLibraryInfo, bytes, 11*time.Minute); err != nil {
|
|
log.Warn(fmt.Sprintf("保存预售缓存数据异常:%v", err))
|
|
}
|
|
})
|
|
return resp, nil
|
|
}
|
|
|
|
func LibrarySearch(in mediamod.AppLibraryReq) (data mediamod.AppElasticSearchLibraryResponse, err error) {
|
|
var resp mediamod.AppElasticSearchLibraryResponse
|
|
from := int64((in.PageNumber - 1) * (in.PageSize))
|
|
size := int64(in.PageSize + 1)
|
|
|
|
must := elastic.A{
|
|
{"term": elastic.M{"mediaType.keyword": HandleMediaType(in.MediaType)}},
|
|
}
|
|
|
|
// 历史同步数据可能为同一个业务标签生成多个 ID。片库按标签名合并这些
|
|
// ID,避免搜索结果返回的某个旧 ID 在标签详情页查不到同名内容。
|
|
tagIds := HandleTagIds(expandMediaTagAliases(in.TagIds))
|
|
must = append(must, tagIds...)
|
|
|
|
short := HandleLibraryShort(in)
|
|
// 根据数据结构组装数据
|
|
query := elastic.M{
|
|
"query": elastic.M{
|
|
"bool": elastic.M{
|
|
"must": must,
|
|
},
|
|
},
|
|
"sort": short,
|
|
"from": from,
|
|
"size": size,
|
|
}
|
|
|
|
res, err := mediamod.SearchByCondWithTotal(query)
|
|
if err != nil {
|
|
return resp, nil
|
|
}
|
|
hasNext := false
|
|
if uint64(len(res.Hits)) > in.PageSize {
|
|
res.Hits = res.Hits[:in.PageSize]
|
|
hasNext = true
|
|
}
|
|
esMedias := make([]mediamod.ESMedia, len(res.Hits))
|
|
for i := range res.Hits {
|
|
esMedias[i] = res.Hits[i].Source
|
|
}
|
|
|
|
videosIDs := make([]primitive.ObjectID, len(esMedias))
|
|
for i, v := range esMedias {
|
|
videosIDs[i] = v.ID
|
|
}
|
|
if len(videosIDs) > int(size) {
|
|
hasNext = true
|
|
videosIDs = videosIDs[:size]
|
|
}
|
|
log.Info(fmt.Sprintf("search media mIds:%v", videosIDs))
|
|
|
|
mediaList, _, err := mediadata.GetListFromCache(in.Filter(videosIDs), 0, int64(in.Limit()), in.Options())
|
|
if err != nil {
|
|
return resp, err
|
|
}
|
|
mediaList = orderMediaByIDs(mediaList, videosIDs)
|
|
resp.HasNext = hasNext
|
|
|
|
if len(mediaList) <= 0 {
|
|
return resp, nil
|
|
}
|
|
|
|
tagIDs := make([]primitive.ObjectID, 0)
|
|
for _, item := range mediaList {
|
|
tagIDs = append(tagIDs, item.Tags...)
|
|
}
|
|
tagMap := mediatagser.GetTagsByIDs2Map(tagIDs)
|
|
|
|
for _, item := range mediaList {
|
|
tags, tagDetails := buildDedupTagsAndDetails(item.Tags, tagMap)
|
|
data := &mediamod.AppMediaBase{
|
|
ID: item.ID,
|
|
SortCode: item.SortCode,
|
|
Status: item.Status,
|
|
Title: item.Title,
|
|
Author: item.Anchor,
|
|
HorizontalCover: item.HorizontalCover,
|
|
VerticalCover: item.VerticalCover,
|
|
Tags: tags,
|
|
TagDetails: tagDetails,
|
|
Summary: item.Summary,
|
|
TotalEpisode: item.TotalEpisode,
|
|
UpdateStatus: item.UpdateStatus,
|
|
MediaType: item.MediaType,
|
|
MediaSubType: item.MediaSubType,
|
|
Kind: item.Kind,
|
|
PermissionIconHide: item.PermissionIconHide,
|
|
Permission: item.Permission,
|
|
Price: item.Price,
|
|
Direction: item.Direction,
|
|
FreeTime: item.FreeTime,
|
|
CountComment: item.CountComment,
|
|
CountPurchases: item.CountPurchases,
|
|
CountBrowse: item.CountBrowse,
|
|
CountCollect: item.CountCollect,
|
|
CountLike: item.CountLike,
|
|
CountView: item.CountView,
|
|
Number: item.Number,
|
|
CreatedAt: item.CreatedAt,
|
|
UpdateTime: item.UpdateTime,
|
|
}
|
|
resp.List = append(resp.List, data)
|
|
}
|
|
resp.HasNext = hasNext
|
|
common.Go(func() {
|
|
if len(videosIDs) > 0 {
|
|
//HandleDiffVideo(vidMods, videosIDs)
|
|
}
|
|
})
|
|
return resp, nil
|
|
}
|
|
|
|
// orderMediaByIDs keeps the final response in the exact order returned by Elasticsearch.
|
|
// MongoDB's $in query does not preserve the input ID order, and its copy of a sort field
|
|
// can briefly differ from Elasticsearch while indexes are being synchronized.
|
|
func orderMediaByIDs(mediaList []*mediamod.Media, ids []primitive.ObjectID) []*mediamod.Media {
|
|
mediaByID := make(map[primitive.ObjectID]*mediamod.Media, len(mediaList))
|
|
for _, item := range mediaList {
|
|
if item != nil {
|
|
mediaByID[item.ID] = item
|
|
}
|
|
}
|
|
|
|
ordered := make([]*mediamod.Media, 0, len(mediaList))
|
|
for _, id := range ids {
|
|
if item, ok := mediaByID[id]; ok {
|
|
ordered = append(ordered, item)
|
|
}
|
|
}
|
|
return ordered
|
|
}
|
|
|
|
func HandleShort(key int) elastic.A {
|
|
return elastic.A{{mediamod.AppLibrarySortField(key): elastic.M{"order": "desc"}}}
|
|
}
|
|
|
|
func HandleLibraryShort(in mediamod.AppLibraryReq) elastic.A {
|
|
if HandleMediaType(in.MediaType) == mediamod.MediaTypeDrama && in.SortType == 1 {
|
|
return elastic.A{
|
|
{"sortCode": elastic.M{"order": "desc"}},
|
|
{"createdAt": elastic.M{"order": "desc"}},
|
|
}
|
|
}
|
|
return HandleShort(in.SortType)
|
|
}
|
|
|
|
func HandleTagIds(tagIds []string) elastic.A {
|
|
var tagIdsValue = elastic.A{}
|
|
var allTagIds []primitive.ObjectID
|
|
if len(tagIds) > 0 {
|
|
for t := range tagIds {
|
|
id, err := primitive.ObjectIDFromHex(tagIds[t])
|
|
if err != nil || id.IsZero() {
|
|
continue
|
|
}
|
|
allTagIds = append(allTagIds, id)
|
|
}
|
|
}
|
|
allTagIds = deduplicateObjectIDs(allTagIds)
|
|
|
|
tagIdsValue = append(tagIdsValue,
|
|
elastic.M{"terms": elastic.M{"tags.keyword": allTagIds}},
|
|
)
|
|
|
|
return tagIdsValue
|
|
}
|
|
|
|
func expandMediaTagAliases(tagIDs []string) []string {
|
|
expanded := make([]primitive.ObjectID, 0, len(tagIDs))
|
|
for _, value := range tagIDs {
|
|
id, err := primitive.ObjectIDFromHex(value)
|
|
if err != nil || id.IsZero() {
|
|
continue
|
|
}
|
|
expanded = append(expanded, id)
|
|
|
|
tag, tagErr := mediatagdata.GetInfoFromCache(id)
|
|
if tagErr != nil || tag.Name == "" {
|
|
continue
|
|
}
|
|
aliases, aliasErr := mediatagdata.GetTagIdsByNameFromCache(tag.Name)
|
|
if aliasErr == nil {
|
|
expanded = append(expanded, aliases...)
|
|
}
|
|
}
|
|
|
|
expanded = deduplicateObjectIDs(expanded)
|
|
result := make([]string, len(expanded))
|
|
for i, id := range expanded {
|
|
result[i] = id.Hex()
|
|
}
|
|
return result
|
|
}
|
|
|
|
func deduplicateObjectIDs(ids []primitive.ObjectID) []primitive.ObjectID {
|
|
seen := make(map[primitive.ObjectID]struct{}, len(ids))
|
|
result := make([]primitive.ObjectID, 0, len(ids))
|
|
for _, id := range ids {
|
|
if id.IsZero() {
|
|
continue
|
|
}
|
|
if _, ok := seen[id]; ok {
|
|
continue
|
|
}
|
|
seen[id] = struct{}{}
|
|
result = append(result, id)
|
|
}
|
|
return result
|
|
}
|
|
|
|
func Search(uid uint64, in mediamod.AppSearchReq) (resp mediamod.AppElasticSearchResponse, err error) {
|
|
var mediaType constant.AcgNewsType
|
|
switch in.Kind {
|
|
case 1:
|
|
mediaType = mediamod.MediaTypeVideo
|
|
case 2:
|
|
mediaType = mediamod.MediaTypeImage
|
|
case 3:
|
|
mediaType = mediamod.MediaTypeText
|
|
case 4:
|
|
mediaType = mediamod.MediaTypeDrama
|
|
default:
|
|
return resp, nil
|
|
}
|
|
if in.Kind == 4 {
|
|
defer normalizeDramaSearchLists(&resp)
|
|
}
|
|
|
|
resp, err = searchByKeyWord(uid, in, mediaType)
|
|
if err != nil {
|
|
return resp, err
|
|
}
|
|
|
|
// 本项目使用 关键字 搜索tag名
|
|
in.TagName = in.KeyWord
|
|
|
|
var tagIDFilter interface{}
|
|
var responseTagID primitive.ObjectID
|
|
if in.Kind == 4 {
|
|
tagIDs, tagErr := mediatagdata.GetTagIdsByNameFromCache(in.TagName)
|
|
if tagErr != nil {
|
|
log.Error("通过标签搜索短剧错误", log.Any("TagName", in.TagName), log.E(tagErr))
|
|
return resp, tagErr
|
|
}
|
|
if len(tagIDs) == 0 {
|
|
return resp, nil
|
|
}
|
|
tagIDFilter = bson.M{"$in": tagIDs}
|
|
responseTagID = tagIDs[0]
|
|
} else {
|
|
tag, tagErr := mediatagdata.GetTagByNameFromCache(in.TagName)
|
|
if tagErr != nil {
|
|
log.Error("通过标签搜索ACG内容错误", log.Any("TagName", in.TagName), log.E(tagErr))
|
|
return resp, tagErr
|
|
}
|
|
if tag.ID.IsZero() {
|
|
return resp, nil
|
|
}
|
|
tagIDFilter = tag.ID
|
|
responseTagID = tag.ID
|
|
}
|
|
filter := bson.M{
|
|
"mediaType": mediaType,
|
|
"tags": tagIDFilter,
|
|
"status": 1,
|
|
"isDelete": false,
|
|
}
|
|
sort := bson.D{{Key: "createdAt", Value: -1}} // 默认最新
|
|
switch in.SortType {
|
|
case 1:
|
|
// 最新
|
|
sort = bson.D{{Key: "createdAt", Value: -1}}
|
|
case 2:
|
|
//最多观看
|
|
sort = bson.D{{Key: "countBrowse", Value: -1}}
|
|
}
|
|
if in.Kind == 4 {
|
|
sort = in.Options()
|
|
}
|
|
mediaList, _, err := mediadata.GetListFromCache(filter, 0, 6, sort)
|
|
if err != nil {
|
|
log.Error("通过标签搜索ACG内容错误", log.Any("filter", filter), log.E(err))
|
|
return
|
|
}
|
|
if in.Kind == 4 {
|
|
resp.TagMediaList = FillMedias(mediaList, uid, true)
|
|
} else {
|
|
resp.TagMediaList = mapLegacySearchMedias(mediaList, true)
|
|
}
|
|
resp.TagID = responseTagID.Hex()
|
|
|
|
return resp, nil
|
|
}
|
|
|
|
func normalizeDramaSearchLists(resp *mediamod.AppElasticSearchResponse) {
|
|
if resp.List == nil {
|
|
resp.List = []*mediamod.AppMediaBase{}
|
|
}
|
|
if resp.TagMediaList == nil {
|
|
resp.TagMediaList = []*mediamod.AppMediaBase{}
|
|
}
|
|
}
|
|
|
|
func searchByKeyWord(uid uint64, in mediamod.AppSearchReq, mediaType string) (resp mediamod.AppElasticSearchResponse, err error) {
|
|
esMedias, err := mediamod.DirectSearch(in.KeyWord, mediaType, int64(in.Skip()), int64(in.Limit()+1))
|
|
if err != nil {
|
|
log.Error("搜索ACG内容错误", log.E(err))
|
|
return resp, nil
|
|
}
|
|
esMediasLen := len(esMedias)
|
|
if esMediasLen == 0 {
|
|
return resp, err
|
|
}
|
|
if esMediasLen > int(in.PageSize) {
|
|
resp.HasNext = true
|
|
esMedias = esMedias[:esMediasLen-1]
|
|
}
|
|
var mIds []primitive.ObjectID
|
|
for _, v := range esMedias {
|
|
mIds = append(mIds, v.ID)
|
|
}
|
|
filter := bson.M{"_id": bson.M{"$in": mIds}, "mediaType": mediaType, "status": 1, "isDelete": false}
|
|
|
|
sort := in.Options()
|
|
keepSearchOrder := in.Kind == 4 && in.SortType != 2
|
|
if keepSearchOrder {
|
|
sort = bson.D{}
|
|
}
|
|
mediaList, _, err := mediadata.GetListFromCache(filter, 0, int64(in.PageSize), sort)
|
|
if err != nil {
|
|
return resp, err
|
|
}
|
|
|
|
if len(mediaList) <= 0 {
|
|
return resp, nil
|
|
}
|
|
|
|
if keepSearchOrder {
|
|
// MongoDB 的 $in 不保留 ID 顺序,恢复短剧关键词搜索的相关度顺序。
|
|
mediaList = orderMediaByIDs(mediaList, mIds)
|
|
}
|
|
if in.Kind == 4 {
|
|
resp.List = FillMedias(mediaList, uid, true)
|
|
} else {
|
|
resp.List = mapLegacySearchMedias(mediaList, false)
|
|
}
|
|
|
|
return resp, nil
|
|
}
|
|
|
|
func mapLegacySearchMedias(mediaList []*mediamod.Media, tagResult bool) []*mediamod.AppMediaBase {
|
|
result := make([]*mediamod.AppMediaBase, 0, len(mediaList))
|
|
for _, item := range mediaList {
|
|
data := &mediamod.AppMediaBase{
|
|
ID: item.ID, SortCode: item.SortCode, Status: item.Status, Title: item.Title,
|
|
HorizontalCover: item.HorizontalCover, VerticalCover: item.VerticalCover,
|
|
Tags: item.Tags, Summary: item.Summary, TotalEpisode: item.TotalEpisode,
|
|
UpdateStatus: item.UpdateStatus, MediaType: item.MediaType, Kind: item.Kind,
|
|
PermissionIconHide: item.PermissionIconHide, Permission: item.Permission,
|
|
Price: item.Price, Direction: item.Direction, FreeTime: item.FreeTime,
|
|
CountComment: item.CountComment, CountPurchases: item.CountPurchases,
|
|
CountBrowse: item.CountBrowse, CountCollect: item.CountCollect,
|
|
CountLike: item.CountLike, CountView: item.CountView, Number: item.Number,
|
|
CreatedAt: item.CreatedAt, UpdateTime: item.UpdateTime,
|
|
}
|
|
if tagResult {
|
|
data.Author = item.Anchor
|
|
data.MediaSubType = item.MediaSubType
|
|
}
|
|
result = append(result, data)
|
|
}
|
|
return result
|
|
}
|
|
|
|
func HandleMediaType(key string) string {
|
|
var moduleTypeValue string
|
|
switch key {
|
|
case "video":
|
|
moduleTypeValue = mediamod.MediaTypeVideo
|
|
case "image":
|
|
moduleTypeValue = mediamod.MediaTypeImage
|
|
case "text":
|
|
moduleTypeValue = mediamod.MediaTypeText
|
|
case "drama":
|
|
moduleTypeValue = mediamod.MediaTypeDrama
|
|
default:
|
|
moduleTypeValue = mediamod.MediaTypeVideo
|
|
}
|
|
return moduleTypeValue
|
|
}
|
|
|
|
func HandleKindType(key string) int {
|
|
var kindValue int
|
|
switch key {
|
|
case "1":
|
|
kindValue = mediamod.RiFan
|
|
case "2":
|
|
kindValue = mediamod.ThreeD
|
|
case "3":
|
|
kindValue = mediamod.FanAnimation
|
|
case "4":
|
|
kindValue = mediamod.Offprint
|
|
case "5":
|
|
kindValue = mediamod.ComicStrip
|
|
case "6":
|
|
kindValue = mediamod.KoreanCartoon
|
|
default:
|
|
kindValue = mediamod.RiFan
|
|
}
|
|
return kindValue
|
|
}
|
|
|
|
type AppGetTopicReq struct {
|
|
SID string `json:"sId" form:"sId"` // 专题ID
|
|
Kind int `json:"kind" form:"kind"` // 种类(1、哩番,2、3D,3、同人动画,4、单行本,5、连载漫画,6、韩漫 7、小说 )
|
|
SortType int `form:"sortType" bson:"sortType"` // 排序 1-最新 2-最多观看 3-最多喜欢(收藏)
|
|
Type int `json:"type" form:"type"` // 0-默认专题这些页面获取 1-首页获取(猜你喜欢)
|
|
commod.Page
|
|
}
|
|
|
|
func (p *AppGetTopicReq) Filter() bson.M {
|
|
var query = bson.M{}
|
|
id, _ := primitive.ObjectIDFromHex(p.SID)
|
|
if p.Type != 1 && p.SID != "" {
|
|
query["sId"] = id
|
|
}
|
|
if p.Kind > 0 {
|
|
query["kind"] = p.Kind
|
|
}
|
|
if p.Type == 1 {
|
|
// 获取专题的模块id
|
|
sId, _ := primitive.ObjectIDFromHex(p.SID)
|
|
section, _ := modulesectionmod.GetBySectionByID(sId)
|
|
query["mId"] = section.SubModuleID
|
|
}
|
|
query["status"] = 1
|
|
query["isDelete"] = false
|
|
return query
|
|
}
|
|
|
|
func (p *AppGetTopicReq) Options() bson.D {
|
|
var sort bson.D
|
|
switch p.SortType {
|
|
case 1:
|
|
// 1、最新
|
|
sort = bson.D{{"createdAt", -1}}
|
|
case 2:
|
|
// 2、最多观看
|
|
sort = bson.D{{"countBrowse", -1}}
|
|
case 3:
|
|
// 3 最多喜欢(收藏)
|
|
sort = bson.D{{"countCollect", -1}}
|
|
case 4: // 4 热评排序
|
|
sort = bson.D{{"hot", -1}, {"createdAt", -1}}
|
|
default:
|
|
sort = bson.D{{"createdAt", -1}}
|
|
}
|
|
return sort
|
|
}
|
|
|
|
type AppGetTopicRes struct {
|
|
HasNext bool `json:"hasNext" bson:"hasNext"` // 是否有下一页
|
|
Section AppSection `json:"section" bson:"section"` // 播单详情
|
|
List []*mediamod.AppMediaBase `json:"list" bson:"list"` // 列表
|
|
}
|
|
|
|
type AppSection struct {
|
|
ID primitive.ObjectID `json:"id" bson:"id"` // ID
|
|
Name string `json:"name" bson:"name" ` // 播单名称
|
|
Cover string `json:"cover" bson:"cover"` // 播单封面
|
|
Count int64 `json:"count" bson:"count"` // 作品数量
|
|
Type int `json:"type" bson:"type"` // 播单类型
|
|
LikeCount int64 `json:"likeCount" bson:"likeCount"` // 点赞数量
|
|
CommentCount int64 `json:"commentCount" bson:"commentCount"` // 评论数量
|
|
UserID uint64 `json:"userId" bson:"userId"` // 用户ID
|
|
UserName string `json:"userName" bson:"userName"` // 用户名称
|
|
Portrait string `json:"portrait" bson:"portrait"` // 用户头像
|
|
//MediaStatus mediamod.MediaStatus `json:"mediaStatus" bson:"mediaStatus"` // 媒体状态
|
|
}
|
|
|
|
func (p *AppGetTopicReq) getTopicListHomePage() (res AppGetTopicRes, err error) {
|
|
mediaList, hasNext, err := mediadata.GetListFromCache(p.Filter(), int64(p.Skip()), int64(p.Limit()), p.Options())
|
|
if err != nil {
|
|
return res, err
|
|
}
|
|
res.List = FillNotStatusMedias(mediaList, false)
|
|
res.HasNext = hasNext
|
|
return
|
|
}
|
|
|
|
// GetTopicList 获取详情
|
|
func (p *AppGetTopicReq) GetTopicList(uid uint64) (res AppGetTopicRes, err error) {
|
|
if p.Type == 1 {
|
|
return p.getTopicListHomePage()
|
|
}
|
|
// 获取播单数据
|
|
sId, _ := primitive.ObjectIDFromHex(p.SID)
|
|
section, err := modulesectionmod.GetBySectionByID(sId)
|
|
if err != nil {
|
|
return res, err
|
|
}
|
|
|
|
res, err = p.getMediaList(uid, section)
|
|
common.Go(func() {
|
|
t := time.Now()
|
|
date := t.Add(-12 * time.Hour).Local().Format("2006-01-02")
|
|
sectionstatmod.UpsertSectionHits(sId, date)
|
|
})
|
|
return
|
|
}
|
|
|
|
// 获取专题相关的acg
|
|
func (p *AppGetTopicReq) getMediaList(uid uint64, section modulesectionmod.Section) (res AppGetTopicRes, err error) {
|
|
var (
|
|
mediaContentIds []primitive.ObjectID
|
|
mStatus map[primitive.ObjectID]mediamod.MediaStatus
|
|
)
|
|
|
|
mediaContentIds = append(mediaContentIds, section.ID)
|
|
|
|
mediaList, hasNext, err := mediadata.GetListFromCache(p.Filter(), int64(p.Skip()), int64(p.Limit()), p.Options())
|
|
if err != nil {
|
|
return res, err
|
|
}
|
|
res.HasNext = hasNext
|
|
|
|
//if len(mediaList) <= 0 {
|
|
// var wg sync.WaitGroup
|
|
// wg.Add(1)
|
|
// common.Go(func() {
|
|
// defer wg.Done()
|
|
// mStatus = GetUserStatus(uid, mediaContentIds)
|
|
// })
|
|
// wg.Wait()
|
|
// res.Section.MediaStatus = mStatus[section.ID]
|
|
// return res, nil
|
|
//}
|
|
|
|
for _, m := range mediaList {
|
|
mediaContentIds = append(mediaContentIds, m.ID)
|
|
}
|
|
|
|
//var wg sync.WaitGroup
|
|
//wg.Add(1)
|
|
//common.Go(func() {
|
|
// defer wg.Done()
|
|
// mStatus = GetUserStatus(uid, mediaContentIds)
|
|
//})
|
|
//wg.Wait()
|
|
//res.Section.MediaStatus = mStatus[section.ID]
|
|
|
|
for _, item := range mediaList {
|
|
data := &mediamod.AppMediaBase{
|
|
ID: item.ID,
|
|
SortCode: item.SortCode,
|
|
Status: item.Status,
|
|
Title: item.Title,
|
|
Author: item.Anchor,
|
|
HorizontalCover: item.HorizontalCover,
|
|
VerticalCover: item.VerticalCover,
|
|
UpdateStatus: item.UpdateStatus,
|
|
Tags: item.Tags,
|
|
Summary: item.Summary,
|
|
TotalEpisode: item.TotalEpisode,
|
|
MediaType: item.MediaType,
|
|
MediaSubType: item.MediaSubType,
|
|
Kind: item.Kind,
|
|
PermissionIconHide: item.PermissionIconHide,
|
|
Permission: item.Permission,
|
|
Price: item.Price,
|
|
Direction: item.Direction,
|
|
FreeTime: item.FreeTime,
|
|
CountComment: item.CountComment,
|
|
CountPurchases: item.CountPurchases,
|
|
CountBrowse: item.CountBrowse,
|
|
CountCollect: item.CountCollect,
|
|
CountLike: item.CountLike,
|
|
CountView: item.CountView,
|
|
Number: item.Number,
|
|
MediaStatus: mStatus[item.ID],
|
|
CreatedAt: item.CreatedAt,
|
|
UpdateTime: item.UpdateTime,
|
|
}
|
|
res.List = append(res.List, data)
|
|
}
|
|
|
|
return res, nil
|
|
}
|
|
|
|
type AppRecommendReq struct {
|
|
TagId string `json:"tagId" form:"tagId"` // 标签id
|
|
MediaType string `json:"mediaType" form:"mediaType"` // 媒体类型 "video":视频,"image":图片,"text":小说
|
|
IsAudio bool `json:"isAudio" form:"isAudio"` // 是否是音频小说
|
|
commod.Page
|
|
}
|
|
|
|
func (p *AppRecommendReq) Filter(media *mediamod.Media) bson.M {
|
|
var query = bson.M{
|
|
"mediaType": media.MediaType,
|
|
"isDelete": false,
|
|
}
|
|
return query
|
|
}
|
|
|
|
func (p *AppRecommendReq) Options() bson.D {
|
|
sort := bson.D{{"_id", -1}, {"createdAt", -1}}
|
|
return sort
|
|
}
|
|
|
|
type AppRecommendRes struct {
|
|
HasNext bool `json:"hasNext" bson:"hasNext"` // 是否有下一页
|
|
List []*MediaRecommend `json:"list" bson:"list"` // 推荐动漫/小说详情页列表
|
|
}
|
|
|
|
type ComicsRecommend struct {
|
|
SimilarRecommend []*mediamod.AppMediaBase `json:"similarRecommend"` // 相似推荐
|
|
HotRecommend []*MediaRecommend `json:"hotRecommend"` // 热门推荐
|
|
DiamondFeatured []*MediaRecommend `json:"diamondFeatured"` // 钻石精选
|
|
}
|
|
|
|
type MediaRecommend struct {
|
|
ID primitive.ObjectID `json:"id" bson:"_id,omitempty"` // 文档id
|
|
Title string `json:"title" bson:"title"` // 标题
|
|
HorizontalCover string `json:"horizontalCover" bson:"horizontalCover"` // 横版封面
|
|
VerticalCover string `json:"verticalCover" bson:"verticalCover"` // 竖版封面
|
|
Tags []primitive.ObjectID `json:"tags" bson:"tags"` // 标签
|
|
TagDetails []mediamod.TagDetail `json:"tagDetails" bson:"tagDetails"` // 标签对象
|
|
TotalEpisode int `json:"totalEpisode" bson:"totalEpisode"` // 总集数
|
|
UpdateStatus int `json:"updateStatus" bson:"updateStatus"` // 更新状态 1-连载中 2-已完结
|
|
MediaType string `json:"mediaType" bson:"mediaType"` // 媒体类型 "video":视频,"image":图片,"text":小说
|
|
MediaSubType mediamod.MediaSubType `json:"mediaSubType" bson:"mediaSubType"` // 子类型 ,暂时只有小说使用 0-默认文本小说 1-有声小说
|
|
Permission int `json:"permission" bson:"permission"` // 收听权限 0:会员 1:金币购买 2:免费
|
|
Price int64 `json:"price" bson:"price"` // 价格(整部购买的类型 小说 cos 写真)
|
|
Direction int64 `json:"direction" bson:"direction"` // 排版方向 0横 1竖(冗余字段)
|
|
CurrentEpisode int `json:"currentEpisode" bson:"currentEpisode"` // 当前更新的集数
|
|
Anchor string `json:"anchor" bson:"anchor"` // 作者
|
|
}
|
|
|
|
// GetList 获取推荐列表
|
|
func (p *AppRecommendReq) GetList(uid uint64) (res AppRecommendRes, err error) {
|
|
tagId, _ := primitive.ObjectIDFromHex(p.TagId)
|
|
// 获取动漫/小说推荐
|
|
filter := bson.M{"mediaType": p.MediaType}
|
|
if !tagId.IsZero() {
|
|
filter["tags"] = tagId
|
|
}
|
|
if p.IsAudio {
|
|
filter["mediaSubType"] = 1
|
|
}
|
|
list, hasNext, err := mediadata.GetListFromCache(filter, int64(p.Skip()), int64(p.Limit()), bson.D{{Key: "countLike", Value: -1}, {Key: "createdAt", Value: -1}})
|
|
if err != nil {
|
|
return
|
|
}
|
|
res.HasNext = hasNext
|
|
for _, v := range list {
|
|
res.List = append(res.List, p.MediaToMediaRecommend(v))
|
|
}
|
|
return res, nil
|
|
}
|
|
|
|
func (p *AppRecommendReq) MediaToMediaRecommend(media *mediamod.Media) *MediaRecommend {
|
|
return &MediaRecommend{
|
|
ID: media.ID,
|
|
Title: media.Title,
|
|
HorizontalCover: media.HorizontalCover,
|
|
VerticalCover: media.VerticalCover,
|
|
Tags: media.Tags,
|
|
TagDetails: media.TagDetails,
|
|
TotalEpisode: media.TotalEpisode,
|
|
UpdateStatus: media.UpdateStatus,
|
|
MediaType: media.MediaType,
|
|
MediaSubType: media.MediaSubType,
|
|
Permission: media.Permission,
|
|
Price: media.Price,
|
|
CurrentEpisode: media.CurrentEpisode,
|
|
Direction: media.Direction,
|
|
Anchor: media.Anchor,
|
|
}
|
|
}
|
|
|
|
type RankingReq struct {
|
|
Type int `json:"type" form:"type"` // 1-日榜 2-周榜 3-月榜 4-总榜 5-年榜
|
|
MediaType string `json:"mediaType" form:"mediaType"` // video 动画 image 漫画 text 小说
|
|
commod.Page
|
|
}
|
|
|
|
type RankingResp struct {
|
|
List []*mediamod.AppMediaBase `json:"list"`
|
|
HasNext bool `json:"hasNext"`
|
|
}
|
|
|
|
const (
|
|
DailyRank = 1 // 日榜
|
|
WeekRank = 2 // 周榜
|
|
MonthRank = 3 // 周榜
|
|
AllRank = 4 // 总榜
|
|
YearRank = 5 // 年榜 180天
|
|
)
|
|
|
|
func (q *RankingReq) List() (res RankingResp, err error) {
|
|
start := time.Now()
|
|
defer func() {
|
|
t := time.Now().UnixMilli() - start.UnixMilli()
|
|
log.Info("RankList", log.Any("ranking.Typ", q.Type), log.Any("耗时", fmt.Sprintf("%v ms", t)))
|
|
}()
|
|
switch q.Type {
|
|
case DailyRank, WeekRank, MonthRank:
|
|
// 日榜
|
|
res, err = q.getRank(q.Type, q.MediaType)
|
|
|
|
case AllRank, YearRank:
|
|
res, err = q.getAllRank(q.MediaType, q.Type == YearRank)
|
|
}
|
|
return
|
|
}
|
|
|
|
func (q *RankingReq) getAllRank(mediaType string, isYear bool) (res RankingResp, err error) {
|
|
// 通过id获取media
|
|
filter := bson.M{"mediaType": mediaType, "status": 1, "isDelete": false}
|
|
if isYear {
|
|
filter["createdAt"] = bson.M{"$gte": timeutil.BeginningOfDay(time.Now())}
|
|
}
|
|
mediaList, hasNext, err := mediadata.GetListFromCache(filter, int64(q.Skip()), int64(q.Limit()), bson.D{{Key: "countBrowse", Value: -1}})
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
res.List = FillNotStatusMedias(mediaList, false)
|
|
res.HasNext = hasNext
|
|
return res, nil
|
|
}
|
|
|
|
func (q *RankingReq) getRank(rankinType int, mediaType string) (res RankingResp, err error) {
|
|
var list []string
|
|
var hasNext bool
|
|
switch rankinType {
|
|
case DailyRank:
|
|
list, _, hasNext = dailytop.GetTopByPage(topser.TypeMedia(mediaType), int64(q.Skip()), int64(q.Limit()))
|
|
case WeekRank:
|
|
list, _, hasNext = weektop.GetTopByPage(topser.TypeMedia(mediaType), int64(q.Skip()), int64(q.Limit()))
|
|
case MonthRank:
|
|
list, _, hasNext = monthtop.GetTopByPage(topser.TypeMedia(mediaType), int64(q.Skip()), int64(q.Limit()))
|
|
default:
|
|
return
|
|
}
|
|
|
|
ids := []primitive.ObjectID{}
|
|
for _, v := range list {
|
|
id, _ := primitive.ObjectIDFromHex(v)
|
|
if id.IsZero() {
|
|
continue
|
|
}
|
|
ids = append(ids, id)
|
|
}
|
|
// 通过id获取media
|
|
mediaList, _, err := mediadata.GetListFromCache(bson.M{"_id": bson.M{"$in": ids}}, 0, int64(q.Limit()), bson.D{})
|
|
if err != nil {
|
|
return
|
|
}
|
|
mediaMap := make(map[primitive.ObjectID]*mediamod.Media)
|
|
for _, v := range mediaList {
|
|
mediaMap[v.ID] = v
|
|
}
|
|
for _, id := range ids {
|
|
item, ok := mediaMap[id]
|
|
if !ok {
|
|
topasist.Remove(topser.TypeMedia(mediaType), id.Hex())
|
|
continue
|
|
}
|
|
if item.Status != 1 {
|
|
topasist.Remove(topser.TypeMedia(mediaType), id.Hex())
|
|
}
|
|
res.List = append(res.List, FillNotStatusMedias([]*mediamod.Media{item}, false)...)
|
|
}
|
|
res.HasNext = hasNext
|
|
return res, nil
|
|
|
|
}
|
|
|
|
type HotReq struct {
|
|
Type int `json:"type" form:"type"` // 0-最新热播 1-本月最热 2-上月最热
|
|
MediaType string `json:"mediaType" form:"mediaType"` // video 动画(默认不填显示这个) image 漫画 text 小说
|
|
commod.Page
|
|
}
|
|
|
|
type HotResp struct {
|
|
List []*mediamod.AppMediaBase `json:"list"`
|
|
HasNext bool `json:"hasNext"`
|
|
}
|
|
|
|
func (p *HotReq) List() (resp HotResp, err error) {
|
|
filter := bson.M{
|
|
"status": 1,
|
|
"isDelete": false,
|
|
"mediaType": "video", // 默认展示动漫
|
|
}
|
|
now := time.Now()
|
|
year, month, day := now.Date()
|
|
// 获取今日最后一刻的时间,这里不能直接使用now去做筛选条件,不然根据这些筛选条件生成的redis key,会一直变,导致一直没有命中缓存
|
|
now = time.Date(year, month, day, 23, 59, 59, 0, now.Location())
|
|
// 默认最新热播
|
|
start := now.AddDate(0, 0, -7)
|
|
end := now
|
|
switch p.Type {
|
|
case 1:
|
|
// 本月最热
|
|
start = now.AddDate(0, -1, 0)
|
|
case 2:
|
|
// 上月最热
|
|
start = now.AddDate(0, -2, 0)
|
|
end = now.AddDate(0, -1, 0)
|
|
default:
|
|
// 判断是否是本周三,再往前多查7天
|
|
if carbon.Now().DayOfWeek() <= 3 {
|
|
start = now.AddDate(0, 0, -14)
|
|
}
|
|
}
|
|
if p.MediaType != "" {
|
|
filter["mediaType"] = p.MediaType
|
|
}
|
|
filter["createdAt"] = bson.M{"$gte": start, "$lt": end}
|
|
|
|
mediaList, hasNext, err := mediadata.GetListFromCache(filter, int64(p.Skip()), int64(p.Limit()), bson.D{{Key: "countCollect", Value: -1}})
|
|
if err != nil {
|
|
return
|
|
}
|
|
for _, item := range mediaList {
|
|
tmp := &mediamod.AppMediaBase{
|
|
ID: item.ID,
|
|
SortCode: item.SortCode,
|
|
Status: item.Status,
|
|
Title: item.Title,
|
|
Author: item.Anchor,
|
|
HorizontalCover: item.HorizontalCover,
|
|
VerticalCover: item.VerticalCover,
|
|
Tags: item.Tags,
|
|
Summary: item.Summary,
|
|
TotalEpisode: item.TotalEpisode,
|
|
MediaType: item.MediaType,
|
|
MediaSubType: item.MediaSubType,
|
|
Kind: item.Kind,
|
|
PermissionIconHide: item.PermissionIconHide,
|
|
Permission: item.Permission,
|
|
Price: item.Price,
|
|
Direction: item.Direction,
|
|
FreeTime: item.FreeTime,
|
|
CountComment: item.CountComment,
|
|
CountPurchases: item.CountPurchases,
|
|
CountBrowse: item.CountBrowse,
|
|
CountCollect: item.CountCollect,
|
|
CountLike: item.CountLike,
|
|
CountView: item.CountView,
|
|
Number: item.Number,
|
|
CreatedAt: item.CreatedAt,
|
|
UpdateTime: item.UpdateTime,
|
|
}
|
|
resp.List = append(resp.List, tmp)
|
|
}
|
|
resp.HasNext = hasNext
|
|
return
|
|
}
|
|
|
|
type MyBuyReq struct {
|
|
MediaType string `json:"mediaType" form:"mediaType"` // video 动画 image 漫画 text 小说 drama 短剧
|
|
commod.Page
|
|
}
|
|
|
|
type MyBuyResp struct {
|
|
List []*mediamod.AppMediaBase `json:"list"`
|
|
HasNext bool `json:"hasNext"`
|
|
Total int64 `json:"total"`
|
|
}
|
|
|
|
func (p *MyBuyReq) List(uid uint64) (resp MyBuyResp, err error) {
|
|
if p.MediaType == mediamod.MediaTypeDrama {
|
|
buyList, total, hasNext, queryErr := media_buy_record_mod.GetMyBuyMediaIDs(uid, p.MediaType, p.Skip(), p.Limit())
|
|
if queryErr != nil {
|
|
return resp, queryErr
|
|
}
|
|
ids := make([]primitive.ObjectID, 0, len(buyList))
|
|
for _, item := range buyList {
|
|
ids = append(ids, item.MediaID)
|
|
}
|
|
_, mediaMap, queryErr := mediamod.GetListByIds(ids)
|
|
if queryErr != nil {
|
|
return resp, queryErr
|
|
}
|
|
ordered := make([]*mediamod.Media, 0, len(ids))
|
|
for _, id := range ids {
|
|
media, ok := mediaMap[id]
|
|
if !ok || media.MediaType != mediamod.MediaTypeDrama || media.Status != 1 || media.IsDelete {
|
|
continue
|
|
}
|
|
copy := media
|
|
ordered = append(ordered, ©)
|
|
}
|
|
resp.List = FillMedias(ordered, uid, true)
|
|
if resp.List == nil {
|
|
resp.List = make([]*mediamod.AppMediaBase, 0)
|
|
}
|
|
resp.Total, resp.HasNext = total, hasNext
|
|
return resp, nil
|
|
}
|
|
res, hasNext, err := media_buy_record_mod.GetMyBuy(uid, p.MediaType, p.Skip(), p.Limit())
|
|
if err != nil {
|
|
return
|
|
}
|
|
ids := []primitive.ObjectID{}
|
|
for _, v := range res {
|
|
ids = append(ids, v.MediaId)
|
|
}
|
|
mediaList, _, err := mediamod.GetListByIds(ids)
|
|
if err != nil {
|
|
return
|
|
}
|
|
for _, item := range mediaList {
|
|
tmp := &mediamod.AppMediaBase{
|
|
ID: item.ID,
|
|
SortCode: item.SortCode,
|
|
Status: item.Status,
|
|
Title: item.Title,
|
|
Author: item.Anchor,
|
|
HorizontalCover: item.HorizontalCover,
|
|
VerticalCover: item.VerticalCover,
|
|
Tags: item.Tags,
|
|
Summary: item.Summary,
|
|
TotalEpisode: item.TotalEpisode,
|
|
MediaType: item.MediaType,
|
|
MediaSubType: item.MediaSubType,
|
|
Kind: item.Kind,
|
|
PermissionIconHide: item.PermissionIconHide,
|
|
Permission: item.Permission,
|
|
Price: item.Price,
|
|
Direction: item.Direction,
|
|
FreeTime: item.FreeTime,
|
|
CountComment: item.CountComment,
|
|
CountPurchases: item.CountPurchases,
|
|
CountBrowse: item.CountBrowse,
|
|
CountCollect: item.CountCollect,
|
|
CountLike: item.CountLike,
|
|
CountView: item.CountView,
|
|
Number: item.Number,
|
|
CreatedAt: item.CreatedAt,
|
|
UpdateTime: item.UpdateTime,
|
|
}
|
|
resp.List = append(resp.List, tmp)
|
|
}
|
|
resp.HasNext = hasNext
|
|
return
|
|
}
|
|
|
|
type (
|
|
AppGetMediaListByTagReq struct {
|
|
commod.Page
|
|
TagId string `form:"tagId" json:"tagId"`
|
|
SortType int `form:"sortType" json:"sortType"` // 排序 1-最新 2-最热 3-最多收藏
|
|
}
|
|
AppGetMediaListByTagRep = AppListRes
|
|
)
|
|
|
|
type TagMediaListReq struct {
|
|
TagID string `form:"tagID" json:"tagID" binding:"required"` // 标签id
|
|
SortType int `form:"sortType" json:"sortType" binding:"required"` //排序类型 1最多播放,2、最新,3、 最多收藏 "
|
|
commod.Page
|
|
}
|
|
|
|
type TagMediaListResp struct {
|
|
HasNext bool `json:"hasNext"`
|
|
List []*mediamod.AppMediaBase `json:"list"`
|
|
}
|
|
|
|
func (p *TagMediaListReq) GetList() (resp TagMediaListResp, err error) {
|
|
tagId, _ := primitive.ObjectIDFromHex(p.TagID)
|
|
if tagId.IsZero() {
|
|
return
|
|
}
|
|
filter := bson.M{
|
|
"tags": tagId,
|
|
"isDelete": false,
|
|
"status": 1,
|
|
}
|
|
|
|
sort := bson.D{{"createdAt", -1}}
|
|
switch p.SortType {
|
|
case 1:
|
|
sort = bson.D{{"countBrowse", -1}, {"createdAt", -1}}
|
|
case 2:
|
|
sort = bson.D{{"createdAt", -1}}
|
|
case 3:
|
|
sort = bson.D{{"countCollect", -1}, {"createdAt", -1}}
|
|
case 4:
|
|
sort = bson.D{{"hot", -1}, {"createdAt", -1}}
|
|
}
|
|
// 获取列表
|
|
var data []*mediamod.Media
|
|
data, resp.HasNext, err = mediadata.GetListFromCache(filter, int64(p.Skip()), int64(p.Limit()), sort)
|
|
if err != nil {
|
|
return
|
|
}
|
|
resp.List = FillNotStatusMedias(data, false)
|
|
|
|
return resp, nil
|
|
}
|