This commit is contained in:
www.xueximeng.com
2025-10-30 18:01:08 +08:00
parent 4df4ad5952
commit 8d318d6441
2 changed files with 191 additions and 164 deletions

View File

@@ -33,9 +33,9 @@ import (
// 插件配置参数
const (
MaxConcurrentUsers = 10 // 最多使用的用户数
MaxConcurrentDetails = 50 // 最大并发详情请求数
DebugLog = false // 调试日志开关排查问题时改为true
MaxConcurrentUsers = 10 // 最多使用的用户数
MaxConcurrentDetails = 50 // 最大并发详情请求数
DebugLog = false // 调试日志开关排查问题时改为true
)
// 默认账户配置可通过Web界面添加更多账户
@@ -382,9 +382,10 @@ const HTMLTemplate = `<!DOCTYPE html>
// GyingPlugin 插件结构
type GyingPlugin struct {
*plugin.BaseAsyncPlugin
users sync.Map // 内存缓存hash -> *User
scrapers sync.Map // cloudscraper实例缓存hash -> *cloudscraper.Scraper
mu sync.RWMutex
users sync.Map // 内存缓存hash -> *User
scrapers sync.Map // cloudscraper实例缓存hash -> *cloudscraper.Scraper
mu sync.RWMutex
searchCache sync.Map // 插件级缓存:关键词->model.PluginSearchResult
}
// User 用户数据结构
@@ -419,8 +420,8 @@ type SearchData struct {
// DetailData 详情接口JSON数据结构
type DetailData struct {
Code int `json:"code"`
WP bool `json:"wp"`
Code int `json:"code"`
WP bool `json:"wp"`
Panlist struct {
ID []string `json:"id"`
Name []string `json:"name"`
@@ -489,41 +490,63 @@ func (p *GyingPlugin) Search(keyword string, ext map[string]interface{}) ([]mode
// 2. 有自己的用户会话管理
// 3. Service层已经有缓存无需插件层再次缓存
func (p *GyingPlugin) SearchWithResult(keyword string, ext map[string]interface{}) (model.PluginSearchResult, error) {
if DebugLog {
fmt.Printf("[Gying] ========== 开始搜索: %s ==========\n", keyword)
}
// 解析 ext["refresh"]
forceRefresh := false
if ext != nil {
if v, ok := ext["refresh"]; ok {
if b, ok := v.(bool); ok && b {
forceRefresh = true
}
}
}
// 1. 获取所有有效用户
users := p.getActiveUsers()
if DebugLog {
fmt.Printf("[Gying] 找到 %d 个有效用户\n", len(users))
}
if !forceRefresh {
if cacheItem, ok := p.searchCache.Load(keyword); ok {
cached := cacheItem.(model.PluginSearchResult)
if DebugLog {
fmt.Printf("[Gying] 命中插件缓存: %s\n", keyword)
}
return cached, nil
}
} else {
if DebugLog {
fmt.Printf("[Gying] 强制刷新,此次跳过插件缓存,关键词: %s\n", keyword)
}
}
if len(users) == 0 {
if DebugLog {
fmt.Printf("[Gying] 没有有效用户,返回空结果\n")
}
return model.PluginSearchResult{Results: []model.SearchResult{}, IsFinal: true}, nil
}
// 2. 限制用户数量
if len(users) > MaxConcurrentUsers {
sort.Slice(users, func(i, j int) bool {
return users[i].LastAccessAt.After(users[j].LastAccessAt)
})
users = users[:MaxConcurrentUsers]
}
// 3. 并发执行搜索
results := p.executeSearchTasks(users, keyword)
if DebugLog {
fmt.Printf("[Gying] 搜索完成,获得 %d 条结果\n", len(results))
}
return model.PluginSearchResult{
Results: results,
IsFinal: true,
}, nil
// 原有真实抓取逻辑
if DebugLog {
fmt.Printf("[Gying] searchWithScraper REAL 执行: %s\n", keyword)
}
users := p.getActiveUsers()
if DebugLog {
fmt.Printf("[Gying] 找到 %d 个有效用户\n", len(users))
}
if len(users) == 0 {
if DebugLog {
fmt.Printf("[Gying] 没有有效用户,返回空结果\n")
}
return model.PluginSearchResult{Results: []model.SearchResult{}, IsFinal: true}, nil
}
if len(users) > MaxConcurrentUsers {
sort.Slice(users, func(i, j int) bool {
return users[i].LastAccessAt.After(users[j].LastAccessAt)
})
users = users[:MaxConcurrentUsers]
}
results := p.executeSearchTasks(users, keyword)
if DebugLog {
fmt.Printf("[Gying] 搜索完成,获得 %d 条结果\n", len(results))
}
realResult := model.PluginSearchResult{
Results: results,
IsFinal: true,
}
// 写入缓存
if len(results) > 0 {
p.searchCache.Store(keyword, realResult)
}
return realResult, nil
}
// ============ 用户管理 ============
@@ -800,13 +823,13 @@ func (p *GyingPlugin) handleGetStatus(c *gin.Context, hash string) {
}
respondSuccess(c, "获取成功", gin.H{
"hash": hash,
"logged_in": loggedIn,
"status": user.Status,
"username_masked": user.UsernameMasked,
"login_time": user.LoginAt.Format("2006-01-02 15:04:05"),
"expire_time": user.ExpireAt.Format("2006-01-02 15:04:05"),
"expires_in_days": expiresInDays,
"hash": hash,
"logged_in": loggedIn,
"status": user.Status,
"username_masked": user.UsernameMasked,
"login_time": user.LoginAt.Format("2006-01-02 15:04:05"),
"expire_time": user.ExpireAt.Format("2006-01-02 15:04:05"),
"expires_in_days": expiresInDays,
})
}
@@ -1026,9 +1049,9 @@ func (p *GyingPlugin) createScraperWithCookies(cookieStr string) (*cloudscraper.
// 创建cloudscraper实例配置以保护cookies不被刷新
scraper, err := cloudscraper.New(
cloudscraper.WithSessionConfig(
false, // refreshOn403 = false禁用403时自动刷新
365*24*time.Hour, // interval = 1年基本不刷新
0, // maxRetries = 0
false, // refreshOn403 = false禁用403时自动刷新
365*24*time.Hour, // interval = 1年基本不刷新
0, // maxRetries = 0
),
)
if err != nil {
@@ -1060,8 +1083,8 @@ func (p *GyingPlugin) createScraperWithCookies(cookieStr string) (*cloudscraper.
for name, value := range cookies {
cookie := &http.Cookie{
Name: name,
Value: value,
Name: name,
Value: value,
// 不设置Domain和Path让cookiejar根据URL自动推导
// cookiejar.SetCookies会根据提供的URL自动设置正确的Domain和Path
}
@@ -1124,9 +1147,9 @@ func parseCookieString(cookieStr string) map[string]string {
// doLogin 执行登录返回scraper实例和cookie字符串
//
// 登录流程3步
// 1. GET登录页 (https://www.gying.net/user/login/) → 获取PHPSESSID
// 2. POST登录 (https://www.gying.net/user/login) → 获取BT_auth、BT_cookietime等认证cookies
// 3. GET详情页 (https://www.gying.net/mv/wkMn) → 触发防爬cookies (vrg_sc、vrg_go等)
// 1. GET登录页 (https://www.gying.net/user/login/) → 获取PHPSESSID
// 2. POST登录 (https://www.gying.net/user/login) → 获取BT_auth、BT_cookietime等认证cookies
// 3. GET详情页 (https://www.gying.net/mv/wkMn) → 触发防爬cookies (vrg_sc、vrg_go等)
//
// 返回: (*cloudscraper.Scraper, cookie字符串, error)
func (p *GyingPlugin) doLogin(username, password string) (*cloudscraper.Scraper, string, error) {
@@ -1140,9 +1163,9 @@ func (p *GyingPlugin) doLogin(username, password string) (*cloudscraper.Scraper,
// 关键配置禁用403自动刷新,防止cookie被清空
scraper, err := cloudscraper.New(
cloudscraper.WithSessionConfig(
false, // refreshOn403 = false禁用403时自动刷新重要
365*24*time.Hour, // interval = 1年基本不刷新
0, // maxRetries = 0
false, // refreshOn403 = false禁用403时自动刷新重要
365*24*time.Hour, // interval = 1年基本不刷新
0, // maxRetries = 0
),
)
if err != nil {
@@ -2232,4 +2255,3 @@ func (p *GyingPlugin) markInactiveUsers() int {
return markedCount
}

View File

@@ -1227,6 +1227,11 @@ func (s *SearchService) searchPlugins(keyword string, plugins []string, forceRef
ext = make(map[string]interface{})
}
// 关键将forceRefresh同步到插件ext["refresh"]
if forceRefresh {
ext["refresh"] = true
}
// 生成缓存键
cacheKey := cache.GeneratePluginCacheKey(keyword, plugins)