feat:添加热榜功能并添加了增加热度的方法。

This commit is contained in:
Leon
2025-12-26 22:49:17 +08:00
parent 14a905e194
commit 328fae5f07
12 changed files with 327 additions and 10 deletions

View File

@@ -10,10 +10,11 @@ import (
type CommentHandler struct {
service *CommentService
accountService *account.AccountService
videoService *VideoService
}
func NewCommentHandler(service *CommentService, accountService *account.AccountService) *CommentHandler {
return &CommentHandler{service: service, accountService: accountService}
func NewCommentHandler(service *CommentService, accountService *account.AccountService, videoService *VideoService) *CommentHandler {
return &CommentHandler{service: service, accountService: accountService, videoService: videoService}
}
func (h *CommentHandler) PublishComment(c *gin.Context) {
var req PublishCommentRequest
@@ -49,6 +50,10 @@ func (h *CommentHandler) PublishComment(c *gin.Context) {
c.JSON(400, gin.H{"error": err.Error()})
return
}
if err := h.videoService.UpdatePopularity(c.Request.Context(), req.VideoID, 1); err != nil {
c.JSON(500, gin.H{"error": err.Error()})
return
}
c.JSON(200, gin.H{"message": "comment published successfully"})
}
@@ -71,6 +76,7 @@ func (h *CommentHandler) DeleteComment(c *gin.Context) {
c.JSON(400, gin.H{"error": err.Error()})
return
}
c.JSON(200, gin.H{"message": "comment deleted successfully"})
}

View File

@@ -12,7 +12,3 @@ type Like struct {
type LikeRequest struct {
VideoID uint `json:"video_id"`
}
type LikeHandler struct {
service *LikeService
}

View File

@@ -6,8 +6,13 @@ import (
"github.com/gin-gonic/gin"
)
func NewLikeHandler(service *LikeService) *LikeHandler {
return &LikeHandler{service: service}
type LikeHandler struct {
service *LikeService
videoService *VideoService
}
func NewLikeHandler(service *LikeService, videoService *VideoService) *LikeHandler {
return &LikeHandler{service: service, videoService: videoService}
}
func (lh *LikeHandler) Like(c *gin.Context) {
@@ -35,6 +40,10 @@ func (lh *LikeHandler) Like(c *gin.Context) {
c.JSON(500, gin.H{"error": err.Error()})
return
}
if err := lh.videoService.UpdatePopularity(c.Request.Context(), req.VideoID, 1); err != nil {
c.JSON(500, gin.H{"error": err.Error()})
return
}
c.JSON(200, gin.H{"message": "like success"})
}
@@ -63,6 +72,10 @@ func (lh *LikeHandler) Unlike(c *gin.Context) {
c.JSON(500, gin.H{"error": err.Error()})
return
}
if err := lh.videoService.UpdatePopularity(c.Request.Context(), req.VideoID, -1); err != nil {
c.JSON(500, gin.H{"error": err.Error()})
return
}
c.JSON(200, gin.H{"message": "unlike success"})
}

View File

@@ -12,6 +12,7 @@ type Video struct {
CoverURL string `gorm:"type:varchar(255);not null" json:"cover_url"`
CreateTime time.Time `gorm:"autoCreateTime" json:"create_time"`
LikesCount int64 `gorm:"column:likes_count;not null;default:0" json:"likes_count"`
Popularity int64 `gorm:"column:popularity;not null;default:0" json:"popularity"`
}
type PublishVideoRequest struct {

View File

@@ -68,3 +68,12 @@ func (vr *VideoRepository) IsExist(ctx context.Context, id uint) (bool, error) {
}
return true, nil
}
func (vr *VideoRepository) UpdatePopularity(ctx context.Context, id uint, change int64) error {
if err := vr.db.WithContext(ctx).Model(&Video{}).
Where("id = ?", id).
Update("popularity", gorm.Expr("popularity + ?", change)).Error; err != nil {
return err
}
return nil
}

View File

@@ -5,6 +5,7 @@ import (
"encoding/json"
"errors"
"fmt"
"strconv"
"strings"
"time"
@@ -166,3 +167,26 @@ func (vs *VideoService) UpdateLikesCount(ctx context.Context, id uint, likesCoun
}
return nil
}
func (vs *VideoService) UpdatePopularity(ctx context.Context, id uint, change int64) error {
if err := vs.repo.UpdatePopularity(ctx, id, change); err != nil {
return err
}
if vs.cache != nil {
// 1) 详情缓存:直接失效(最简单靠谱)
_ = vs.cache.Del(context.Background(), fmt.Sprintf("video:detail:id=%d", id))
// 2) 热榜写到“时间窗ZSET”不要用 detail key
now := time.Now().UTC().Truncate(time.Minute)
windowKey := "hot:video:1m:" + now.Format("200601021504")
member := strconv.FormatUint(uint64(id), 10)
opCtx, cancel := context.WithTimeout(ctx, 50*time.Millisecond)
defer cancel()
_ = vs.cache.ZincrBy(opCtx, windowKey, member, float64(change))
_ = vs.cache.Expire(opCtx, windowKey, 2*time.Hour)
}
return nil
}