@@ -0,0 +1,241 @@
|
||||
package dramaser
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"91porn-server/app/appg"
|
||||
"91porn-server/app/service/mediaser"
|
||||
"91porn-server/common/dramatopic"
|
||||
"91porn-server/common/log"
|
||||
"91porn-server/models/commod"
|
||||
"91porn-server/models/v/mediamod"
|
||||
"91porn-server/models/v/modulesectionmod"
|
||||
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||
"go.mongodb.org/mongo-driver/mongo/options"
|
||||
)
|
||||
|
||||
const everyoneLikesCacheTTL = 30 * time.Second
|
||||
|
||||
type TopicSummary struct {
|
||||
TopicID string `json:"topicId"`
|
||||
Name string `json:"name"`
|
||||
TopicType string `json:"topicType"`
|
||||
SystemKey string `json:"systemKey"`
|
||||
Sort int `json:"sort"`
|
||||
WorkCount int64 `json:"workCount"`
|
||||
}
|
||||
|
||||
type TopicListResponse struct {
|
||||
List []TopicSummary `json:"list"`
|
||||
}
|
||||
|
||||
type TopicWorksRequest struct {
|
||||
TopicID string `form:"topicId" json:"topicId" binding:"required"`
|
||||
commod.Page
|
||||
}
|
||||
|
||||
type TopicWorksResponse struct {
|
||||
Topic TopicSummary `json:"topic"`
|
||||
Total int64 `json:"total"`
|
||||
HasNext bool `json:"hasNext"`
|
||||
List []*mediamod.AppMediaBase `json:"list"`
|
||||
}
|
||||
|
||||
func GetTopics(now time.Time) (TopicListResponse, error) {
|
||||
moduleID, ok, err := dramatopic.ModuleID(now)
|
||||
if err != nil {
|
||||
return TopicListResponse{}, err
|
||||
}
|
||||
total, err := mediamod.QueryAllCount(activeDramaFilter())
|
||||
if err != nil {
|
||||
return TopicListResponse{}, err
|
||||
}
|
||||
sections := make([]modulesectionmod.Section, 0)
|
||||
if ok {
|
||||
sections, err = modulesectionmod.ListBySubModule(moduleID, 1000)
|
||||
if err != nil {
|
||||
return TopicListResponse{}, err
|
||||
}
|
||||
}
|
||||
sectionIDs := make([]primitive.ObjectID, 0, len(sections))
|
||||
for _, section := range sections {
|
||||
if section.Status != nil && *section.Status == 1 {
|
||||
sectionIDs = append(sectionIDs, section.ID)
|
||||
}
|
||||
}
|
||||
counts, err := mediamod.CountActiveDramaBySectionIDs(sectionIDs)
|
||||
if err != nil {
|
||||
return TopicListResponse{}, err
|
||||
}
|
||||
items := make([]topicSortItem, 0, 3+len(sections))
|
||||
for _, system := range dramatopic.SystemTopics() {
|
||||
items = append(items, topicSortItem{summary: TopicSummary{
|
||||
TopicID: system.ID, Name: system.Name, TopicType: dramatopic.TypeSystem,
|
||||
SystemKey: system.SystemKey, Sort: system.Sort, WorkCount: total,
|
||||
}, systemOrder: system.TieOrder})
|
||||
}
|
||||
for _, section := range sections {
|
||||
if section.Status == nil || *section.Status != 1 {
|
||||
continue
|
||||
}
|
||||
items = append(items, topicSortItem{summary: TopicSummary{
|
||||
TopicID: section.ID.Hex(), Name: section.SectionName, TopicType: dramatopic.TypeCustom,
|
||||
Sort: valueOrZero(section.Sort), WorkCount: counts[section.ID],
|
||||
}, updatedAt: section.UpdatedAt})
|
||||
}
|
||||
sortTopicItems(items)
|
||||
response := TopicListResponse{List: make([]TopicSummary, 0, len(items))}
|
||||
for _, item := range items {
|
||||
response.List = append(response.List, item.summary)
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
type topicSortItem struct {
|
||||
summary TopicSummary
|
||||
systemOrder int
|
||||
updatedAt time.Time
|
||||
}
|
||||
|
||||
func sortTopicItems(items []topicSortItem) {
|
||||
sort.SliceStable(items, func(i, j int) bool {
|
||||
if items[i].summary.Sort != items[j].summary.Sort {
|
||||
return items[i].summary.Sort > items[j].summary.Sort
|
||||
}
|
||||
if items[i].systemOrder != items[j].systemOrder {
|
||||
return items[i].systemOrder > items[j].systemOrder
|
||||
}
|
||||
return items[i].updatedAt.After(items[j].updatedAt)
|
||||
})
|
||||
}
|
||||
|
||||
func GetTopicWorks(uid uint64, req TopicWorksRequest, now time.Time) (TopicWorksResponse, error) {
|
||||
if system, ok := dramatopic.FindSystem(req.TopicID); ok {
|
||||
return getSystemTopicWorks(uid, req, system)
|
||||
}
|
||||
moduleID, ok, err := dramatopic.ModuleID(now)
|
||||
if err != nil || !ok {
|
||||
if err == nil {
|
||||
err = errors.New("短剧专题模块未配置")
|
||||
}
|
||||
return TopicWorksResponse{}, err
|
||||
}
|
||||
topicID, err := primitive.ObjectIDFromHex(req.TopicID)
|
||||
if err != nil {
|
||||
return TopicWorksResponse{}, errors.New("无效的专题ID")
|
||||
}
|
||||
section, err := modulesectionmod.GetBySectionByID(topicID)
|
||||
if err != nil || section.SubModuleID != moduleID || section.DeletedAt != nil || section.Status == nil || *section.Status != 1 {
|
||||
if err == nil {
|
||||
err = errors.New("专题不存在或已停用")
|
||||
}
|
||||
return TopicWorksResponse{}, err
|
||||
}
|
||||
filter := activeDramaFilter()
|
||||
filter["sId"] = topicID
|
||||
total, err := mediamod.QueryAllCount(filter)
|
||||
if err != nil {
|
||||
return TopicWorksResponse{}, err
|
||||
}
|
||||
list, err := mediamod.QueryAllList(filter, options.Find().
|
||||
SetSkip(req.Skip64()).SetLimit(req.Limit64()+1).
|
||||
SetSort(bson.D{{Key: "sectionSort", Value: -1}, {Key: "latestPublishedAt", Value: -1}, {Key: "_id", Value: -1}}))
|
||||
if err != nil {
|
||||
return TopicWorksResponse{}, err
|
||||
}
|
||||
hasNext := len(list) > int(req.PageSize)
|
||||
if hasNext {
|
||||
list = list[:req.PageSize]
|
||||
}
|
||||
return TopicWorksResponse{
|
||||
Topic: TopicSummary{TopicID: req.TopicID, Name: section.SectionName, TopicType: dramatopic.TypeCustom, Sort: valueOrZero(section.Sort), WorkCount: total},
|
||||
Total: total, HasNext: hasNext, List: fillTopicMedias(list, uid),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func getSystemTopicWorks(uid uint64, req TopicWorksRequest, topic dramatopic.SystemTopic) (TopicWorksResponse, error) {
|
||||
filter := activeDramaFilter()
|
||||
total, err := mediamod.QueryAllCount(filter)
|
||||
if err != nil {
|
||||
return TopicWorksResponse{}, err
|
||||
}
|
||||
var list []*mediamod.Media
|
||||
var hasNext bool
|
||||
if topic.ID == dramatopic.IDEveryone {
|
||||
list, err = listEveryoneLikes(req.Skip64(), req.Limit64()+1)
|
||||
if err != nil {
|
||||
return TopicWorksResponse{}, err
|
||||
}
|
||||
hasNext = len(list) > int(req.PageSize)
|
||||
if hasNext {
|
||||
list = list[:req.PageSize]
|
||||
}
|
||||
} else {
|
||||
sortBy := bson.D{{Key: "sortCode", Value: -1}, {Key: "latestPublishedAt", Value: -1}, {Key: "_id", Value: -1}}
|
||||
if topic.ID == dramatopic.IDLatest {
|
||||
sortBy = bson.D{{Key: "latestPublishedAt", Value: -1}, {Key: "createdAt", Value: -1}, {Key: "_id", Value: -1}}
|
||||
}
|
||||
list, err = mediamod.QueryAllList(filter, options.Find().SetSkip(req.Skip64()).SetLimit(req.Limit64()+1).SetSort(sortBy))
|
||||
if err != nil {
|
||||
return TopicWorksResponse{}, err
|
||||
}
|
||||
hasNext = len(list) > int(req.PageSize)
|
||||
if hasNext {
|
||||
list = list[:req.PageSize]
|
||||
}
|
||||
}
|
||||
return TopicWorksResponse{
|
||||
Topic: TopicSummary{TopicID: topic.ID, Name: topic.Name, TopicType: dramatopic.TypeSystem, SystemKey: topic.SystemKey, Sort: topic.Sort, WorkCount: total},
|
||||
Total: total, HasNext: hasNext, List: fillTopicMedias(list, uid),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func fillTopicMedias(list []*mediamod.Media, uid uint64) []*mediamod.AppMediaBase {
|
||||
filled := mediaser.FillMedias(list, uid, true)
|
||||
if filled == nil {
|
||||
return []*mediamod.AppMediaBase{}
|
||||
}
|
||||
return filled
|
||||
}
|
||||
|
||||
func listEveryoneLikes(skip, limit int64) ([]*mediamod.Media, error) {
|
||||
key := fmt.Sprintf("drama:topic:everyone-likes:v1:%d:%d", skip, limit)
|
||||
if appg.Redis != nil {
|
||||
cached, err := appg.Redis.Get(key)
|
||||
if err == nil && cached != nil {
|
||||
var list []*mediamod.Media
|
||||
if jsonErr := json.Unmarshal([]byte(*cached), &list); jsonErr == nil {
|
||||
return list, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
list, err := mediamod.ListActiveDramaByInteractionScore(skip, limit)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if appg.Redis != nil {
|
||||
if data, marshalErr := json.Marshal(list); marshalErr == nil {
|
||||
if cacheErr := appg.Redis.Set(key, data, everyoneLikesCacheTTL); cacheErr != nil {
|
||||
log.Warn("缓存大家爱看短剧列表失败", log.E(cacheErr))
|
||||
}
|
||||
}
|
||||
}
|
||||
return list, nil
|
||||
}
|
||||
|
||||
func activeDramaFilter() bson.M {
|
||||
return bson.M{"mediaType": mediamod.MediaTypeDrama, "status": 1, "isDelete": false}
|
||||
}
|
||||
|
||||
func valueOrZero(value *int) int {
|
||||
if value == nil {
|
||||
return 0
|
||||
}
|
||||
return *value
|
||||
}
|
||||
Reference in New Issue
Block a user