package playletser import ( "fmt" "net/url" "strconv" "strings" "videoweb/app/service/authser" "videoweb/app/service/upstream" "videoweb/pub/common/log" "github.com/gin-gonic/gin" ) const ( searchPath = "/api/app/playlet/search" defaultSearchPageSize = 25 ) // SearchQuery 搜索分页参数(keyword 对应上游 query)。 type SearchQuery struct { Keyword string PageNum int PageSize int } // Normalize 校正分页默认值。 func (q *SearchQuery) Normalize() { q.Keyword = strings.TrimSpace(q.Keyword) if q.PageNum <= 0 { q.PageNum = 1 } if q.PageSize <= 0 { q.PageSize = defaultSearchPageSize } if q.PageSize > 50 { q.PageSize = 50 } } // FetchSearch ES 分页搜索短剧。 func FetchSearch(c *gin.Context, q SearchQuery) (*PlayletVideoResp, error) { q.Normalize() if q.Keyword == "" { return nil, fmt.Errorf("playlet search keyword is empty") } authser.EnsureGuestOnEnter(c) env, err := fetchSearchOnce(c, q) if err != nil { return nil, err } if env.Code != 200 && authser.IsSessionExpiredCode(env.Code) { if authser.RecoverContentSession(c, env.Code) { env, err = fetchSearchOnce(c, q) if err != nil { return nil, err } } } if env.Code != 200 { return nil, fmt.Errorf("playlet search code=%d msg=%s tip=%s", env.Code, env.Msg, env.Tip) } return &env.Data, nil } func fetchSearchOnce(c *gin.Context, q SearchQuery) (*APIEnvelope[PlayletVideoResp], error) { params := url.Values{} params.Set("pageNum", strconv.Itoa(q.PageNum)) params.Set("pageSize", strconv.Itoa(q.PageSize)) params.Set("keyword", q.Keyword) var env APIEnvelope[PlayletVideoResp] if err := upstream.GetJSON(c, searchPath+"?"+params.Encode(), &env); err != nil { return nil, err } return &env, nil } // FetchSearchOrEmpty 失败时返回空列表。 func FetchSearchOrEmpty(c *gin.Context, q SearchQuery) *PlayletVideoResp { data, err := FetchSearch(c, q) if err != nil { log.Error("fetch playlet search failed", log.E(err)) return &PlayletVideoResp{PageNum: q.PageNum, PageSize: q.PageSize} } if data == nil { return &PlayletVideoResp{PageNum: q.PageNum, PageSize: q.PageSize} } return data } func searchPageURL(keyword string, pageNum int) string { keyword = strings.TrimSpace(keyword) if keyword == "" { return "/search/" } path := "/search/" + url.PathEscape(keyword) if pageNum > 1 { path += "/page/" + strconv.Itoa(pageNum) } return path + "/" } func SearchCanonicalPath(q SearchQuery) string { q.Normalize() return searchPageURL(q.Keyword, q.PageNum) } // BuildSearchPagination 搜索分页。 func BuildSearchPagination(q SearchQuery, totalCount int64) PaginationVM { q.Normalize() return BuildPagination(func(p int) string { return searchPageURL(q.Keyword, p) }, q.PageNum, q.PageSize, totalCount) } // ParseSearchQuery 从站点 query 解析(q → keyword)。 func ParseSearchQuery(qStr, pageStr string) SearchQuery { q := SearchQuery{PageSize: defaultSearchPageSize, Keyword: strings.TrimSpace(qStr)} if n, err := strconv.Atoi(strings.TrimSpace(pageStr)); err == nil { q.PageNum = n } q.Normalize() return q }