Files
谢宇宁andClaude Opus 5.5 3639d2184a Initial commit
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 14:47:17 +07:00

125 lines
3.1 KiB
Go

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
}