feat:添加热榜功能并添加了增加热度的方法。
This commit is contained in:
@@ -6,6 +6,7 @@ import (
|
||||
rediscache "feedsystem_video_go/internal/redis"
|
||||
"feedsystem_video_go/internal/video"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -229,6 +230,114 @@ func (f *FeedService) ListByFollowing(ctx context.Context, limit int, latestBefo
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (f *FeedService) ListByPopularity(ctx context.Context, limit int, reqAsOf int64, offset int, viewerAccountID uint, latestPopularity int64, latestBefore time.Time, latestIDBefore uint) (ListByPopularityResponse, error) {
|
||||
// Redis 热榜(稳定分页:as_of + offset)
|
||||
if f.cache != nil {
|
||||
asOf := time.Now().UTC().Truncate(time.Minute)
|
||||
if reqAsOf > 0 {
|
||||
asOf = time.Unix(reqAsOf, 0).UTC().Truncate(time.Minute)
|
||||
}
|
||||
|
||||
const win = 60
|
||||
keys := make([]string, 0, win)
|
||||
for i := 0; i < win; i++ {
|
||||
keys = append(keys, "hot:video:1m:"+asOf.Add(-time.Duration(i)*time.Minute).Format("200601021504"))
|
||||
}
|
||||
|
||||
dest := "hot:video:merge:1m:" + asOf.Format("200601021504") // 快照key:同一个as_of页内复用
|
||||
opCtx, cancel := context.WithTimeout(ctx, 80*time.Millisecond)
|
||||
defer cancel()
|
||||
|
||||
exists, _ := f.cache.Exists(opCtx, dest)
|
||||
if !exists {
|
||||
_ = f.cache.ZUnionStore(opCtx, dest, keys, "SUM")
|
||||
_ = f.cache.Expire(opCtx, dest, 2*time.Minute) // 给翻页留时间
|
||||
}
|
||||
|
||||
start := int64(offset)
|
||||
stop := start + int64(limit) - 1
|
||||
members, err := f.cache.ZRevRange(opCtx, dest, start, stop)
|
||||
if err == nil && len(members) == 0 {
|
||||
if offset > 0 {
|
||||
return ListByPopularityResponse{
|
||||
VideoList: []FeedVideoItem{},
|
||||
AsOf: asOf.Unix(),
|
||||
NextOffset: offset,
|
||||
HasMore: false,
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
if err == nil && len(members) > 0 {
|
||||
ids := make([]uint, 0, len(members))
|
||||
for _, m := range members {
|
||||
u, err := strconv.ParseUint(m, 10, 64)
|
||||
if err == nil && u > 0 {
|
||||
ids = append(ids, uint(u))
|
||||
}
|
||||
}
|
||||
|
||||
videos, err := f.repo.GetByIDs(ctx, ids)
|
||||
if err == nil {
|
||||
byID := make(map[uint]*video.Video, len(videos))
|
||||
for _, v := range videos {
|
||||
byID[v.ID] = v
|
||||
}
|
||||
ordered := make([]*video.Video, 0, len(ids))
|
||||
for _, id := range ids {
|
||||
if v := byID[id]; v != nil {
|
||||
ordered = append(ordered, v)
|
||||
}
|
||||
}
|
||||
items, err := f.buildFeedVideos(ctx, ordered, viewerAccountID)
|
||||
if err != nil {
|
||||
return ListByPopularityResponse{}, err
|
||||
}
|
||||
resp := ListByPopularityResponse{
|
||||
VideoList: items,
|
||||
AsOf: asOf.Unix(),
|
||||
NextOffset: offset + len(items),
|
||||
HasMore: len(items) == limit,
|
||||
}
|
||||
if len(ordered) > 0 {
|
||||
last := ordered[len(ordered)-1]
|
||||
nextPopularity := last.Popularity
|
||||
nextBefore := last.CreateTime
|
||||
nextID := last.ID
|
||||
resp.NextLatestPopularity = &nextPopularity
|
||||
resp.NextLatestBefore = &nextBefore
|
||||
resp.NextLatestIDBefore = &nextID
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
videos, err := f.repo.ListByPopularity(ctx, limit, latestPopularity, latestBefore, latestIDBefore)
|
||||
if err != nil {
|
||||
return ListByPopularityResponse{}, err
|
||||
}
|
||||
items, err := f.buildFeedVideos(ctx, videos, viewerAccountID)
|
||||
if err != nil {
|
||||
return ListByPopularityResponse{}, err
|
||||
}
|
||||
resp := ListByPopularityResponse{
|
||||
VideoList: items,
|
||||
AsOf: 0,
|
||||
NextOffset: 0,
|
||||
HasMore: len(items) == limit,
|
||||
}
|
||||
if len(videos) > 0 {
|
||||
last := videos[len(videos)-1]
|
||||
nextPopularity := last.Popularity
|
||||
nextBefore := last.CreateTime
|
||||
nextID := last.ID
|
||||
resp.NextLatestPopularity = &nextPopularity
|
||||
resp.NextLatestBefore = &nextBefore
|
||||
resp.NextLatestIDBefore = &nextID
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (f *FeedService) buildFeedVideos(ctx context.Context, videos []*video.Video, viewerAccountID uint) ([]FeedVideoItem, error) {
|
||||
feedVideos := make([]FeedVideoItem, 0, len(videos))
|
||||
videoIDs := make([]uint, len(videos))
|
||||
|
||||
Reference in New Issue
Block a user