Initial commit: web_hghl_server

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-10-26 16:28:14 +08:00
co-authored by Claude Opus 4.7
commit 65fca60622
653 changed files with 135901 additions and 0 deletions
+44
View File
@@ -0,0 +1,44 @@
package homeser
import (
"encoding/json"
"time"
"videoweb/app/api/proto"
"videoweb/pub/common/log"
"videoweb/pub/redis"
)
const (
appHomeCacheKey = "app:home:data"
appHomeCacheTTL = time.Minute * 5
)
// getHomeDataCache 读取 APP 首页 Redis 缓存,缓存异常时降级查库
func getHomeDataCache() *proto.DataResp {
cacheData, err1 := redis.Get(appHomeCacheKey)
if err1 != nil {
log.Warn("读取APP首页缓存失败", log.Any("cacheKey", appHomeCacheKey), log.E(err1))
return nil
}
if cacheData == nil || *cacheData == "" {
return nil
}
resp := &proto.DataResp{}
if err1 := json.Unmarshal([]byte(*cacheData), resp); err1 != nil {
log.Warn("解析APP首页缓存失败", log.Any("cacheKey", appHomeCacheKey), log.E(err1))
return nil
}
return resp
}
// setHomeDataCache 写入 APP 首页 Redis 缓存,缓存异常不影响主流程
func setHomeDataCache(resp proto.DataResp) {
bytes, err1 := json.Marshal(resp)
if err1 != nil {
log.Warn("序列化APP首页缓存失败", log.Any("cacheKey", appHomeCacheKey), log.E(err1))
return
}
if err1 := redis.Set(appHomeCacheKey, string(bytes), appHomeCacheTTL); err1 != nil {
log.Warn("写入APP首页缓存失败", log.Any("cacheKey", appHomeCacheKey), log.E(err1))
}
}
+191
View File
@@ -0,0 +1,191 @@
package homeser
import (
"context"
"sync"
"videoweb/app/api/proto"
"videoweb/app/service/actressser"
"videoweb/app/service/configser"
"videoweb/app/service/playletser"
"videoweb/app/service/translationser"
"videoweb/app/service/videoser"
"videoweb/pub/common/netutil"
"videoweb/pub/common/srvdef"
"videoweb/pub/models/homebannermod"
"github.com/gin-gonic/gin"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo/options"
)
const homeBannerListLimit int64 = 30
var homeBannerAppProjection = bson.D{
{Key: homebannermod.FN.HomeBanner.Id, Value: 1},
{Key: homebannermod.FN.HomeBanner.Name, Value: 1},
{Key: homebannermod.FN.HomeBanner.Image, Value: 1},
{Key: homebannermod.FN.HomeBanner.VerticalImage, Value: 1},
{Key: homebannermod.FN.HomeBanner.Url, Value: 1},
{Key: homebannermod.FN.HomeBanner.Rank, Value: 1},
{Key: homebannermod.FN.HomeBanner.Status, Value: 1},
}
// HomeData 获取首页数据,包含公共配置、公告、广告和各业务首页数据
func HomeData(ctx context.Context) (proto.DataResp, *srvdef.SrvErr) {
if cacheData := getHomeDataCache(); cacheData != nil {
configser.RewriteImageCdn(ctx, cacheData)
return *cacheData, nil
}
// 数据组装
config := configser.GetConfigInfo()
data := proto.DataResp{
Path: homeRequestPath(ctx),
Config: config,
Advitise: configser.GetAdvitise(),
Announcement: configser.GetAnnouncement(),
HomeBannerList: make([]proto.HomeBannerInfo, 0),
PlayletData: proto.HomePlayletDataResp{
RecommendList: make([]proto.PlayletData, 0),
NewestList: make([]proto.PlayletData, 0),
HotList: make([]proto.PlayletData, 0),
},
VideoData: proto.HomeVideoDataResp{
RecommendList: make([]proto.VideoInfo, 0),
NewestList: make([]proto.VideoInfo, 0),
HotList: make([]proto.VideoInfo, 0),
},
ActressInfoList: make([]proto.ActressInfo, 0),
}
// 并分查询
var wg sync.WaitGroup
var mu sync.Mutex
var err1 *srvdef.SrvErr
setErr := func(err *srvdef.SrvErr) {
if err == nil {
return
}
mu.Lock()
defer mu.Unlock()
if err1 == nil {
err1 = err
}
}
wg.Add(4)
go func() {
defer wg.Done()
list, err := HomeBannerList(ctx, config.ImgCdn)
if err != nil {
setErr(err)
return
}
mu.Lock()
data.HomeBannerList = list
mu.Unlock()
}()
go func() {
defer wg.Done()
playletData, err := playletser.HomePlayletData(ctx, config.ImgCdn)
if err != nil {
setErr(err)
return
}
mu.Lock()
data.PlayletData = playletData
mu.Unlock()
}()
go func() {
defer wg.Done()
videoData, err := videoser.HomeVideoDataForHome(ctx, config.ImgCdn)
if err != nil {
setErr(err)
return
}
mu.Lock()
data.VideoData = videoData
mu.Unlock()
}()
go func() {
defer wg.Done()
list, err := actressser.HomeActressData(ctx)
if err != nil {
setErr(err)
return
}
mu.Lock()
data.ActressInfoList = list
mu.Unlock()
}()
wg.Wait()
if err1 != nil {
return data, err1
}
setHomeDataCache(data)
configser.RewriteImageCdn(ctx, &data)
return data, nil
}
// HomeBannerList 查询启用的首页banner信息列表
func HomeBannerList(ctx context.Context, imgCdn string) ([]proto.HomeBannerInfo, *srvdef.SrvErr) {
list, err := homebannermod.FindManyHomeBanner(ctx, bson.M{
homebannermod.FN.HomeBanner.Status: true,
}, options.Find().
SetProjection(homeBannerAppProjection).
SetSort(bson.D{
{Key: homebannermod.FN.HomeBanner.Rank, Value: -1},
{Key: homebannermod.FN.HomeBanner.CreatedAt, Value: -1},
{Key: homebannermod.FN.HomeBanner.Id, Value: -1},
}).
SetLimit(homeBannerListLimit))
if err != nil {
return nil, err
}
result := make([]proto.HomeBannerInfo, 0, len(list))
for _, item := range list {
if item == nil {
continue
}
result = append(result, proto.HomeBannerInfo{
Id: item.Id,
Name: item.Name,
Image: netutil.MergeURL(imgCdn, item.Image),
VerticalImage: netutil.MergeURL(imgCdn, item.VerticalImage),
Url: item.Url,
Rank: item.Rank,
Status: item.Status,
})
}
return result, nil
}
// HomeBaseData 获取首页公共配置数据
func HomeBaseData(ctx context.Context) proto.HomeBaseResp {
resp := proto.HomeBaseResp{
Translations: translationser.GetTranslationData(),
Config: configser.GetRequestConfig(ctx),
BottonTranslations: translationser.GetTranslationBottomList(),
Advitise: configser.GetAdvitise(),
Announcement: configser.GetAnnouncement(),
}
configser.RewriteImageCdn(ctx, &resp)
return resp
}
// HomeTagsData 获取首页标签数据
func HomeTagsData(ctx context.Context) proto.HomeTagsResp {
resp := proto.HomeTagsResp{
HomeBaseResp: HomeBaseData(ctx),
VideoTagsList: configser.GetHomeVideoTagList(),
PlayletTagsList: configser.GetHomePlayletTagList(),
}
configser.RewriteImageCdn(ctx, &resp)
return resp
}
// homeRequestPath 从 gin 上下文中提取当前请求路径,避免 API 层重复组装首页响应字段
func homeRequestPath(ctx context.Context) string {
ginCtx, ok := ctx.(*gin.Context)
if !ok || ginCtx.Request == nil || ginCtx.Request.URL == nil {
return ""
}
return ginCtx.Request.URL.Path
}