285 lines
6.8 KiB
Go
285 lines
6.8 KiB
Go
package web
|
|
|
|
import (
|
|
"fmt"
|
|
"net/url"
|
|
"strings"
|
|
"videoweb/app/service/playletser"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
type searchTrend struct {
|
|
Rank int
|
|
Title string
|
|
Heat string
|
|
Badge string
|
|
}
|
|
|
|
// SearchMobile 移动端搜索入口。
|
|
// 热搜 + 猜你喜欢:GET /api/app/playlet/hot-like
|
|
// 联想:前端调用 GET /api/web/search/suggest → 上游 /api/app/playlet/search/suggest
|
|
// 文档:http://172.104.181.99:25319/swagger/index.html#/app短剧相关接口/get_api_app_playlet_hot_like
|
|
func SearchMobile(c *gin.Context) {
|
|
if hasLegacySearchQuery(c) {
|
|
NotFound(c)
|
|
return
|
|
}
|
|
raw := playletser.FetchHotLikeOrEmpty(c)
|
|
trends := hotSearchTrends(raw.HotSearch)
|
|
recommended := raw.GuessLike
|
|
if len(recommended) > 15 {
|
|
recommended = recommended[:15]
|
|
}
|
|
|
|
HTMLOK(c, "searchMobile.html", gin.H{
|
|
"title": "搜索 - 黄果短剧",
|
|
"query": searchQueryFromRequest(c),
|
|
"trends": trends,
|
|
"recommended": recommended,
|
|
"hotLikeDebug": gin.H{
|
|
"path": "/api/app/playlet/hot-like",
|
|
"response": raw,
|
|
},
|
|
})
|
|
}
|
|
|
|
func hotSearchTrends(items []playletser.PlayletHotSearchItem) []searchTrend {
|
|
out := make([]searchTrend, 0, len(items))
|
|
for i, item := range items {
|
|
keyword := strings.TrimSpace(item.Keyword)
|
|
if keyword == "" {
|
|
continue
|
|
}
|
|
rank := i + 1
|
|
badge := ""
|
|
switch rank {
|
|
case 1:
|
|
badge = "热"
|
|
case 2:
|
|
badge = "新"
|
|
}
|
|
out = append(out, searchTrend{
|
|
Rank: rank,
|
|
Title: keyword,
|
|
Heat: formatSearchHeat(item.Count),
|
|
Badge: badge,
|
|
})
|
|
}
|
|
return out
|
|
}
|
|
|
|
func formatSearchHeat(n int64) string {
|
|
if n <= 0 {
|
|
return "0"
|
|
}
|
|
if n < 10000 {
|
|
return fmt.Sprintf("%d", n)
|
|
}
|
|
v := float64(n) / 10000
|
|
if v >= 100 {
|
|
return fmt.Sprintf("%.0f 万", v)
|
|
}
|
|
return fmt.Sprintf("%.1f 万", v)
|
|
}
|
|
|
|
// Search 搜索结果页:GET /api/app/playlet/search。
|
|
// 文档:http://172.104.181.99:25319/swagger/index.html#/app短剧相关接口/get_api_app_playlet_search
|
|
// 无结果时「大家都在看」:GET /api/app/playlet/all/list(取 6 条最热)。
|
|
func Search(c *gin.Context) {
|
|
if hasLegacySearchQuery(c) {
|
|
NotFound(c)
|
|
return
|
|
}
|
|
keyword := searchQueryFromRequest(c)
|
|
pageStr := strings.TrimSpace(c.Param("page"))
|
|
q := playletser.ParseSearchQuery(keyword, pageStr)
|
|
|
|
list := []playletser.CommonData(nil)
|
|
recommended := []playletser.CommonData(nil)
|
|
total := int64(0)
|
|
pageNum, pageSize := q.PageNum, q.PageSize
|
|
var searchDebug any
|
|
var watchingDebug any
|
|
|
|
if q.Keyword != "" {
|
|
raw := playletser.FetchSearchOrEmpty(c, q)
|
|
searchDebug = gin.H{
|
|
"path": "/api/app/playlet/search",
|
|
"keyword": q.Keyword,
|
|
"pageNum": q.PageNum,
|
|
"pageSize": q.PageSize,
|
|
"response": raw,
|
|
}
|
|
if raw != nil {
|
|
list = raw.List
|
|
total = raw.TotalCount
|
|
if raw.PageNum > 0 {
|
|
pageNum = raw.PageNum
|
|
}
|
|
if raw.PageSize > 0 {
|
|
pageSize = raw.PageSize
|
|
}
|
|
if strings.TrimSpace(raw.Keyword) != "" {
|
|
keyword = raw.Keyword
|
|
}
|
|
}
|
|
} else {
|
|
searchDebug = gin.H{
|
|
"path": "/api/app/playlet/search",
|
|
"keyword": "",
|
|
"note": "empty keyword, skip upstream",
|
|
}
|
|
}
|
|
|
|
if len(list) == 0 {
|
|
watchingQ := playletser.AllListQuery{
|
|
PageNum: 1,
|
|
PageSize: 6,
|
|
SortType: 2, // 最热
|
|
UpdateStatus: 0, // 全部
|
|
}
|
|
watching := playletser.FetchAllListOrEmpty(c, watchingQ)
|
|
watchingDebug = gin.H{
|
|
"path": "/api/app/playlet/all/list",
|
|
"pageNum": watchingQ.PageNum,
|
|
"pageSize": watchingQ.PageSize,
|
|
"sortType": watchingQ.SortType,
|
|
"response": watching,
|
|
}
|
|
if watching != nil {
|
|
recommended = watching.List
|
|
if len(recommended) > 6 {
|
|
recommended = recommended[:6]
|
|
}
|
|
}
|
|
}
|
|
|
|
HTMLOK(c, "search.html", gin.H{
|
|
"title": "搜索 - 黄果短剧",
|
|
"query": keyword,
|
|
"hasResults": len(list) > 0,
|
|
"resultCount": total,
|
|
"works": list,
|
|
"recommended": recommended,
|
|
"pageNum": pageNum,
|
|
"pageSize": pageSize,
|
|
"pagination": playletser.BuildSearchPagination(q, total),
|
|
"searchDebug": searchDebug,
|
|
"watchingDebug": watchingDebug,
|
|
})
|
|
}
|
|
|
|
type searchSuggestFeature struct {
|
|
Title string `json:"title"`
|
|
Cover string `json:"cover"`
|
|
URL string `json:"url"`
|
|
Meta string `json:"meta"`
|
|
}
|
|
|
|
type searchSuggestItem struct {
|
|
Title string `json:"title"`
|
|
Kind string `json:"kind"`
|
|
Query string `json:"query"`
|
|
URL string `json:"url"`
|
|
}
|
|
|
|
// SearchSuggest PC 顶栏输入联想:GET /api/web/search/suggest?keyword=
|
|
// 上游:GET /api/app/playlet/search/suggest → proto.PlayletSearchSuggestResp
|
|
// 文档:http://172.104.181.99:25319/swagger/index.html#/app短剧相关接口/get_api_app_playlet_search_suggest
|
|
func SearchSuggest(c *gin.Context) {
|
|
keyword := strings.TrimSpace(c.Query("keyword"))
|
|
if keyword == "" {
|
|
keyword = strings.TrimSpace(c.Query("q"))
|
|
}
|
|
if keyword == "" {
|
|
c.JSON(200, gin.H{"code": 200, "keyword": "", "feature": nil, "items": []searchSuggestItem{}})
|
|
return
|
|
}
|
|
|
|
raw := playletser.FetchSearchSuggestOrEmpty(c, keyword)
|
|
if kw := strings.TrimSpace(raw.Keyword); kw != "" {
|
|
keyword = kw
|
|
}
|
|
|
|
var feature *searchSuggestFeature
|
|
items := make([]searchSuggestItem, 0, len(raw.List)+1)
|
|
for _, item := range raw.List {
|
|
title := playletser.PlayletDisplayName(item.PlayName, item.Title)
|
|
if title == "" {
|
|
continue
|
|
}
|
|
href := playletser.PlayPath(item.Slug, item.ID)
|
|
if feature == nil {
|
|
feature = &searchSuggestFeature{
|
|
Title: title,
|
|
Cover: strings.TrimSpace(item.Cover),
|
|
URL: href,
|
|
Meta: buildSearchSuggestMeta(item),
|
|
}
|
|
continue
|
|
}
|
|
items = append(items, searchSuggestItem{
|
|
Title: title,
|
|
Kind: "短剧 剧集",
|
|
Query: title,
|
|
URL: href,
|
|
})
|
|
}
|
|
|
|
items = append(items, searchSuggestItem{
|
|
Title: keyword,
|
|
Kind: "搜索",
|
|
Query: keyword,
|
|
URL: playletser.SearchResultsURL(keyword),
|
|
})
|
|
|
|
c.JSON(200, gin.H{
|
|
"code": 200,
|
|
"keyword": keyword,
|
|
"feature": feature,
|
|
"items": items,
|
|
})
|
|
}
|
|
|
|
func buildSearchSuggestMeta(item playletser.CommonData) string {
|
|
parts := make([]string, 0, 4)
|
|
for _, name := range item.ThemeNames {
|
|
name = strings.TrimSpace(name)
|
|
if name != "" {
|
|
parts = append(parts, name)
|
|
}
|
|
}
|
|
for _, name := range item.TagNames {
|
|
name = strings.TrimSpace(name)
|
|
if name != "" && len(parts) < 2 {
|
|
parts = append(parts, name)
|
|
}
|
|
}
|
|
if item.TotalEpisode > 0 {
|
|
parts = append(parts, fmt.Sprintf("全 %d 集", item.TotalEpisode))
|
|
} else if item.UpdateStatus == 1 {
|
|
parts = append(parts, "连载中")
|
|
}
|
|
if anchor := strings.TrimSpace(item.Anchor); anchor != "" && anchor != "暂无" && anchor != "原创" {
|
|
parts = append(parts, "主演 "+anchor)
|
|
}
|
|
return strings.Join(parts, " ")
|
|
}
|
|
|
|
func hasLegacySearchQuery(c *gin.Context) bool {
|
|
query := c.Request.URL.Query()
|
|
return query.Has("q") || query.Has("page")
|
|
}
|
|
|
|
func searchQueryFromRequest(c *gin.Context) string {
|
|
q := strings.TrimSpace(c.Param("q"))
|
|
if q == "" {
|
|
return ""
|
|
}
|
|
if decoded, err := url.PathUnescape(q); err == nil {
|
|
return strings.TrimSpace(decoded)
|
|
}
|
|
return q
|
|
}
|