Files
web_huangguo_web/app/service/playletser/home.go
T

130 lines
3.3 KiB
Go

package playletser
import (
"fmt"
"net/url"
"path"
"strings"
"sync"
"time"
"videoweb/app/service/upstream"
"videoweb/pub/common/log"
"github.com/gin-gonic/gin"
)
const homePath = "/api/app/playlet/home"
const homeCacheTTL = 30 * time.Second
var (
homeMu sync.Mutex
homeCache *HomePlayletResponse
homeAt time.Time
)
// FetchHome 拉取首页短剧聚合数据。
func FetchHome(c *gin.Context) (*HomePlayletResponse, error) {
var env APIEnvelope[HomePlayletResponse]
if err := upstream.GetPublicJSON(c, homePath, &env); err != nil {
return nil, err
}
if env.Code != 200 {
return nil, fmt.Errorf("playlet home code=%d msg=%s", env.Code, env.Msg)
}
return &env.Data, nil
}
// FetchHomeOrEmpty 带短缓存;失败时打日志并返回空结构,保证 SSR 页面可渲染。
func FetchHomeOrEmpty(c *gin.Context) *HomePlayletResponse {
homeMu.Lock()
defer homeMu.Unlock()
if homeCache != nil && time.Since(homeAt) < homeCacheTTL {
return cloneHome(homeCache)
}
data, err := FetchHome(c)
if err != nil {
log.Error("fetch playlet home failed", log.E(err))
if homeCache != nil {
return cloneHome(homeCache)
}
return &HomePlayletResponse{}
}
if data == nil {
if homeCache != nil {
return cloneHome(homeCache)
}
return &HomePlayletResponse{}
}
data.SeoInfo.Normalize()
homeCache = data
homeAt = time.Now()
return cloneHome(homeCache)
}
func cloneHome(src *HomePlayletResponse) *HomePlayletResponse {
if src == nil {
return &HomePlayletResponse{}
}
out := *src
if src.Announcements != nil {
out.Announcements = append([]AnnouncementItem(nil), src.Announcements...)
}
if src.HomeBannerData != nil {
out.HomeBannerData = append([]HomeBannerData(nil), src.HomeBannerData...)
}
if src.HomeTodayUpdateData != nil {
out.HomeTodayUpdateData = append([]CommonData(nil), src.HomeTodayUpdateData...)
}
if src.HomeCategoryData != nil {
out.HomeCategoryData = make([]HomeCategoryData, len(src.HomeCategoryData))
for i, cat := range src.HomeCategoryData {
out.HomeCategoryData[i] = cat
if cat.List != nil {
out.HomeCategoryData[i].List = append([]CommonData(nil), cat.List...)
}
}
}
if src.HomeRecommendThemes != nil {
out.HomeRecommendThemes = append([]HomeRecommendTheme(nil), src.HomeRecommendThemes...)
}
if src.SeoInfo.Keywords != nil {
out.SeoInfo.Keywords = append([]string(nil), src.SeoInfo.Keywords...)
}
return &out
}
// ActiveHomeBanners 过滤未启用项,保留接口返回顺序。
func ActiveHomeBanners(list []HomeBannerData) []HomeBannerData {
if len(list) == 0 {
return list
}
out := make([]HomeBannerData, 0, len(list))
for _, item := range list {
if !item.Status {
continue
}
item.URL = normalizeBannerURL(item.URL)
out = append(out, item)
}
return out
}
// normalizeBannerURL 站内页面链接补尾斜杠,避免后台漏填 "/" 时每次点击都多一次 301。
// 外链、协议相对地址、带扩展名的文件路径保持原样。
func normalizeBannerURL(raw string) string {
raw = strings.TrimSpace(raw)
if !strings.HasPrefix(raw, "/") || strings.HasPrefix(raw, "//") {
return raw
}
u, err := url.Parse(raw)
if err != nil || u.Path == "" || strings.HasSuffix(u.Path, "/") {
return raw
}
if strings.Contains(path.Base(u.Path), ".") {
return raw
}
u.Path += "/"
return u.String()
}