242 lines
7.3 KiB
Go
242 lines
7.3 KiB
Go
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
|
|
}
|