mirror of
https://github.com/fish2018/pansou.git
synced 2025-11-25 03:14:59 +08:00
增加filter过滤
This commit is contained in:
16
README.md
16
README.md
@@ -404,6 +404,7 @@ curl -X POST http://localhost:8888/api/auth/logout
|
|||||||
| plugins | string[] | 否 | 指定搜索的插件列表,不指定则搜索全部插件 |
|
| plugins | string[] | 否 | 指定搜索的插件列表,不指定则搜索全部插件 |
|
||||||
| cloud_types | string[] | 否 | 指定返回的网盘类型列表,支持:baidu、aliyun、quark、tianyi、uc、mobile、115、pikpak、xunlei、123、magnet、ed2k,不指定则返回所有类型 |
|
| cloud_types | string[] | 否 | 指定返回的网盘类型列表,支持:baidu、aliyun、quark、tianyi、uc、mobile、115、pikpak、xunlei、123、magnet、ed2k,不指定则返回所有类型 |
|
||||||
| ext | object | 否 | 扩展参数,用于传递给插件的自定义参数,如{"title_en":"English Title", "is_all":true} |
|
| ext | object | 否 | 扩展参数,用于传递给插件的自定义参数,如{"title_en":"English Title", "is_all":true} |
|
||||||
|
| filter | object | 否 | 过滤配置,用于过滤返回结果。格式:{"include":["关键词1","关键词2"],"exclude":["排除词1","排除词2"]}。include为包含关键词列表(OR关系),exclude为排除关键词列表(AND关系) |
|
||||||
|
|
||||||
**GET请求参数**:
|
**GET请求参数**:
|
||||||
|
|
||||||
@@ -418,6 +419,7 @@ curl -X POST http://localhost:8888/api/auth/logout
|
|||||||
| plugins | string | 否 | 指定搜索的插件列表,使用英文逗号分隔多个插件名,不指定则搜索全部插件 |
|
| plugins | string | 否 | 指定搜索的插件列表,使用英文逗号分隔多个插件名,不指定则搜索全部插件 |
|
||||||
| cloud_types | string | 否 | 指定返回的网盘类型列表,使用英文逗号分隔多个类型,支持:baidu、aliyun、quark、tianyi、uc、mobile、115、pikpak、xunlei、123、magnet、ed2k,不指定则返回所有类型 |
|
| cloud_types | string | 否 | 指定返回的网盘类型列表,使用英文逗号分隔多个类型,支持:baidu、aliyun、quark、tianyi、uc、mobile、115、pikpak、xunlei、123、magnet、ed2k,不指定则返回所有类型 |
|
||||||
| ext | string | 否 | JSON格式的扩展参数,用于传递给插件的自定义参数,如{"title_en":"English Title", "is_all":true} |
|
| ext | string | 否 | JSON格式的扩展参数,用于传递给插件的自定义参数,如{"title_en":"English Title", "is_all":true} |
|
||||||
|
| filter | string | 否 | JSON格式的过滤配置,用于过滤返回结果。格式:{"include":["关键词1","关键词2"],"exclude":["排除词1","排除词2"]} |
|
||||||
|
|
||||||
**POST请求示例**:
|
**POST请求示例**:
|
||||||
|
|
||||||
@@ -448,6 +450,17 @@ curl -X POST http://localhost:8888/api/search \
|
|||||||
"kw": "速度与激情",
|
"kw": "速度与激情",
|
||||||
"res": "merge"
|
"res": "merge"
|
||||||
}'
|
}'
|
||||||
|
|
||||||
|
# 使用过滤器(只返回包含“合集”或“全集”,且不包含“预告”的结果)
|
||||||
|
curl -X POST http://localhost:8888/api/search \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{
|
||||||
|
"kw": "唐朝诡事录",
|
||||||
|
"filter": {
|
||||||
|
"include": ["合集", "全集"],
|
||||||
|
"exclude": ["预告", "花絮"]
|
||||||
|
}
|
||||||
|
}'
|
||||||
```
|
```
|
||||||
|
|
||||||
**GET请求示例**:
|
**GET请求示例**:
|
||||||
@@ -459,6 +472,9 @@ curl "http://localhost:8888/api/search?kw=速度与激情&res=merge&src=tg"
|
|||||||
# 启用认证时(需要添加Authorization头)
|
# 启用认证时(需要添加Authorization头)
|
||||||
curl "http://localhost:8888/api/search?kw=速度与激情&res=merge" \
|
curl "http://localhost:8888/api/search?kw=速度与激情&res=merge" \
|
||||||
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
|
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
|
||||||
|
|
||||||
|
# 使用过滤器(GET方式需要URL编码JSON)
|
||||||
|
curl "http://localhost:8888/api/search?kw=唐朝诡事录&filter=%7B%22include%22%3A%5B%22合集%22%2C%22全集%22%5D%2C%22exclude%22%3A%5B%22预告%22%5D%7D"
|
||||||
```
|
```
|
||||||
|
|
||||||
**成功响应**:
|
**成功响应**:
|
||||||
|
|||||||
140
api/filter.go
Normal file
140
api/filter.go
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"pansou/model"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// applyResultFilter 应用过滤器到搜索响应
|
||||||
|
func applyResultFilter(response model.SearchResponse, filter *model.FilterConfig, resultType string) model.SearchResponse {
|
||||||
|
if filter == nil || (len(filter.Include) == 0 && len(filter.Exclude) == 0) {
|
||||||
|
return response
|
||||||
|
}
|
||||||
|
|
||||||
|
// 预处理关键词(转小写)
|
||||||
|
includeKeywords := make([]string, len(filter.Include))
|
||||||
|
for i, kw := range filter.Include {
|
||||||
|
includeKeywords[i] = strings.ToLower(kw)
|
||||||
|
}
|
||||||
|
|
||||||
|
excludeKeywords := make([]string, len(filter.Exclude))
|
||||||
|
for i, kw := range filter.Exclude {
|
||||||
|
excludeKeywords[i] = strings.ToLower(kw)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据结果类型决定过滤策略
|
||||||
|
if resultType == "merged_by_type" || resultType == "" {
|
||||||
|
// 过滤 merged_by_type 的 note 字段
|
||||||
|
response.MergedByType = filterMergedByType(response.MergedByType, includeKeywords, excludeKeywords)
|
||||||
|
|
||||||
|
// 重新计算 total
|
||||||
|
total := 0
|
||||||
|
for _, links := range response.MergedByType {
|
||||||
|
total += len(links)
|
||||||
|
}
|
||||||
|
response.Total = total
|
||||||
|
} else if resultType == "all" || resultType == "results" {
|
||||||
|
// 过滤 results 的 title 和 links 的 work_title
|
||||||
|
response.Results = filterResults(response.Results, includeKeywords, excludeKeywords)
|
||||||
|
response.Total = len(response.Results)
|
||||||
|
|
||||||
|
// 如果是 all 类型,也需要过滤 merged_by_type
|
||||||
|
if resultType == "all" {
|
||||||
|
response.MergedByType = filterMergedByType(response.MergedByType, includeKeywords, excludeKeywords)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return response
|
||||||
|
}
|
||||||
|
|
||||||
|
// filterMergedByType 过滤 merged_by_type 中的链接
|
||||||
|
func filterMergedByType(mergedLinks model.MergedLinks, includeKeywords, excludeKeywords []string) model.MergedLinks {
|
||||||
|
if mergedLinks == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
filtered := make(model.MergedLinks)
|
||||||
|
|
||||||
|
for linkType, links := range mergedLinks {
|
||||||
|
filteredLinks := make([]model.MergedLink, 0)
|
||||||
|
|
||||||
|
for _, link := range links {
|
||||||
|
if matchFilter(link.Note, includeKeywords, excludeKeywords) {
|
||||||
|
filteredLinks = append(filteredLinks, link)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 只添加非空的类型
|
||||||
|
if len(filteredLinks) > 0 {
|
||||||
|
filtered[linkType] = filteredLinks
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return filtered
|
||||||
|
}
|
||||||
|
|
||||||
|
// filterResults 过滤 results 数组
|
||||||
|
func filterResults(results []model.SearchResult, includeKeywords, excludeKeywords []string) []model.SearchResult {
|
||||||
|
if results == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
filtered := make([]model.SearchResult, 0)
|
||||||
|
|
||||||
|
for _, result := range results {
|
||||||
|
// 先检查 title 是否匹配
|
||||||
|
if !matchFilter(result.Title, includeKeywords, excludeKeywords) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// title 匹配后,过滤 links 中的 work_title
|
||||||
|
filteredLinks := make([]model.Link, 0)
|
||||||
|
for _, link := range result.Links {
|
||||||
|
// 如果 link 有 work_title,检查它;否则使用 result.Title
|
||||||
|
checkText := link.WorkTitle
|
||||||
|
if checkText == "" {
|
||||||
|
checkText = result.Title
|
||||||
|
}
|
||||||
|
|
||||||
|
if matchFilter(checkText, includeKeywords, excludeKeywords) {
|
||||||
|
filteredLinks = append(filteredLinks, link)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 只有有链接的结果才添加
|
||||||
|
if len(filteredLinks) > 0 {
|
||||||
|
result.Links = filteredLinks
|
||||||
|
filtered = append(filtered, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return filtered
|
||||||
|
}
|
||||||
|
|
||||||
|
// matchFilter 检查文本是否匹配过滤条件
|
||||||
|
func matchFilter(text string, includeKeywords, excludeKeywords []string) bool {
|
||||||
|
lowerText := strings.ToLower(text)
|
||||||
|
|
||||||
|
// 检查 exclude(任一匹配则排除)
|
||||||
|
for _, kw := range excludeKeywords {
|
||||||
|
if strings.Contains(lowerText, kw) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查 include(如果有 include 列表,必须至少匹配一个)
|
||||||
|
if len(includeKeywords) > 0 {
|
||||||
|
matched := false
|
||||||
|
for _, kw := range includeKeywords {
|
||||||
|
if strings.Contains(lowerText, kw) {
|
||||||
|
matched = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !matched {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
@@ -130,6 +130,17 @@ func SearchHandler(c *gin.Context) {
|
|||||||
if ext == nil {
|
if ext == nil {
|
||||||
ext = make(map[string]interface{})
|
ext = make(map[string]interface{})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 处理filter参数,JSON格式
|
||||||
|
var filter *model.FilterConfig
|
||||||
|
filterStr := c.Query("filter")
|
||||||
|
if filterStr != "" && filterStr != " " {
|
||||||
|
filter = &model.FilterConfig{}
|
||||||
|
if err := jsonutil.Unmarshal([]byte(filterStr), filter); err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, model.NewErrorResponse(400, "无效的filter参数格式: "+err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
req = model.SearchRequest{
|
req = model.SearchRequest{
|
||||||
Keyword: keyword,
|
Keyword: keyword,
|
||||||
@@ -141,6 +152,7 @@ func SearchHandler(c *gin.Context) {
|
|||||||
Plugins: plugins,
|
Plugins: plugins,
|
||||||
CloudTypes: cloudTypes, // 添加cloud_types到请求中
|
CloudTypes: cloudTypes, // 添加cloud_types到请求中
|
||||||
Ext: ext,
|
Ext: ext,
|
||||||
|
Filter: filter,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// POST方式:从请求体获取
|
// POST方式:从请求体获取
|
||||||
@@ -200,6 +212,11 @@ func SearchHandler(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 应用过滤器
|
||||||
|
if req.Filter != nil {
|
||||||
|
result = applyResultFilter(result, req.Filter, req.ResultType)
|
||||||
|
}
|
||||||
|
|
||||||
// 包装SearchResponse到标准响应格式中
|
// 包装SearchResponse到标准响应格式中
|
||||||
response := model.NewSuccessResponse(result)
|
response := model.NewSuccessResponse(result)
|
||||||
jsonData, _ := jsonutil.Marshal(response)
|
jsonData, _ := jsonutil.Marshal(response)
|
||||||
|
|||||||
@@ -1,5 +1,11 @@
|
|||||||
package model
|
package model
|
||||||
|
|
||||||
|
// FilterConfig 过滤配置
|
||||||
|
type FilterConfig struct {
|
||||||
|
Include []string `json:"include,omitempty"` // 包含关键词列表(OR关系)
|
||||||
|
Exclude []string `json:"exclude,omitempty"` // 排除关键词列表(AND关系)
|
||||||
|
}
|
||||||
|
|
||||||
// SearchRequest 搜索请求参数
|
// SearchRequest 搜索请求参数
|
||||||
type SearchRequest struct {
|
type SearchRequest struct {
|
||||||
Keyword string `json:"kw" binding:"required"` // 搜索关键词
|
Keyword string `json:"kw" binding:"required"` // 搜索关键词
|
||||||
@@ -11,4 +17,5 @@ type SearchRequest struct {
|
|||||||
Plugins []string `json:"plugins"` // 指定搜索的插件列表,不指定则搜索全部插件
|
Plugins []string `json:"plugins"` // 指定搜索的插件列表,不指定则搜索全部插件
|
||||||
Ext map[string]interface{} `json:"ext"` // 扩展参数,用于传递给插件的自定义参数
|
Ext map[string]interface{} `json:"ext"` // 扩展参数,用于传递给插件的自定义参数
|
||||||
CloudTypes []string `json:"cloud_types"` // 指定返回的网盘类型列表,不指定则返回所有类型
|
CloudTypes []string `json:"cloud_types"` // 指定返回的网盘类型列表,不指定则返回所有类型
|
||||||
|
Filter *FilterConfig `json:"filter,omitempty"` // 过滤配置,用于过滤返回结果
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user