2025-07-12 19:53:44 +08:00
|
|
|
|
package jikepan
|
|
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
|
"bytes"
|
|
|
|
|
|
"fmt"
|
2025-07-15 00:03:02 +08:00
|
|
|
|
"io"
|
2025-07-12 19:53:44 +08:00
|
|
|
|
"net/http"
|
|
|
|
|
|
"strings"
|
|
|
|
|
|
"time"
|
|
|
|
|
|
|
|
|
|
|
|
"pansou/model"
|
|
|
|
|
|
"pansou/plugin"
|
2025-07-15 00:03:02 +08:00
|
|
|
|
"pansou/util/json"
|
2025-07-12 19:53:44 +08:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
// 在init函数中注册插件
|
|
|
|
|
|
func init() {
|
2025-07-15 00:03:02 +08:00
|
|
|
|
// 注册插件
|
|
|
|
|
|
plugin.RegisterGlobalPlugin(NewJikepanAsyncV2Plugin())
|
2025-07-12 19:53:44 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const (
|
2025-07-15 00:03:02 +08:00
|
|
|
|
// JikepanAPIURL 即刻盘API地址
|
2025-07-12 19:53:44 +08:00
|
|
|
|
JikepanAPIURL = "https://api.jikepan.xyz/search"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
2025-07-15 00:03:02 +08:00
|
|
|
|
// JikepanAsyncV2Plugin 即刻盘搜索异步V2插件
|
|
|
|
|
|
type JikepanAsyncV2Plugin struct {
|
|
|
|
|
|
*plugin.BaseAsyncPlugin
|
2025-07-12 19:53:44 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-15 00:03:02 +08:00
|
|
|
|
// NewJikepanAsyncV2Plugin 创建新的即刻盘搜索异步V2插件
|
|
|
|
|
|
func NewJikepanAsyncV2Plugin() *JikepanAsyncV2Plugin {
|
|
|
|
|
|
return &JikepanAsyncV2Plugin{
|
|
|
|
|
|
BaseAsyncPlugin: plugin.NewBaseAsyncPlugin("jikepan", 3),
|
2025-07-12 19:53:44 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-15 00:03:02 +08:00
|
|
|
|
// Search 执行搜索并返回结果
|
|
|
|
|
|
func (p *JikepanAsyncV2Plugin) Search(keyword string) ([]model.SearchResult, error) {
|
|
|
|
|
|
// 生成缓存键
|
|
|
|
|
|
cacheKey := keyword
|
|
|
|
|
|
|
|
|
|
|
|
// 使用异步搜索基础方法
|
|
|
|
|
|
return p.AsyncSearch(keyword, cacheKey, p.doSearch)
|
2025-07-12 19:53:44 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-15 00:03:02 +08:00
|
|
|
|
// doSearch 实际的搜索实现
|
|
|
|
|
|
func (p *JikepanAsyncV2Plugin) doSearch(client *http.Client, keyword string) ([]model.SearchResult, error) {
|
2025-07-12 19:53:44 +08:00
|
|
|
|
// 构建请求
|
|
|
|
|
|
reqBody := map[string]interface{}{
|
|
|
|
|
|
"name": keyword,
|
|
|
|
|
|
"is_all": false,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
jsonData, err := json.Marshal(reqBody)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return nil, fmt.Errorf("marshal request failed: %w", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
req, err := http.NewRequest("POST", JikepanAPIURL, bytes.NewBuffer(jsonData))
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return nil, fmt.Errorf("create request failed: %w", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
req.Header.Set("Content-Type", "application/json")
|
|
|
|
|
|
req.Header.Set("referer", "https://jikepan.xyz/")
|
|
|
|
|
|
req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36")
|
|
|
|
|
|
|
|
|
|
|
|
// 发送请求
|
2025-07-15 00:03:02 +08:00
|
|
|
|
resp, err := client.Do(req)
|
2025-07-12 19:53:44 +08:00
|
|
|
|
if err != nil {
|
|
|
|
|
|
return nil, fmt.Errorf("request failed: %w", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
defer resp.Body.Close()
|
|
|
|
|
|
|
|
|
|
|
|
// 解析响应
|
|
|
|
|
|
var apiResp JikepanResponse
|
2025-07-15 00:03:02 +08:00
|
|
|
|
bodyBytes, err := io.ReadAll(resp.Body)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return nil, fmt.Errorf("read response body failed: %w", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if err := json.Unmarshal(bodyBytes, &apiResp); err != nil {
|
2025-07-12 19:53:44 +08:00
|
|
|
|
return nil, fmt.Errorf("decode response failed: %w", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 检查响应状态
|
|
|
|
|
|
if apiResp.Msg != "success" {
|
|
|
|
|
|
return nil, fmt.Errorf("API returned error: %s", apiResp.Msg)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 转换结果格式
|
2025-07-15 00:03:02 +08:00
|
|
|
|
results := p.convertResults(apiResp.List)
|
|
|
|
|
|
|
|
|
|
|
|
return results, nil
|
2025-07-12 19:53:44 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// convertResults 将API响应转换为标准SearchResult格式
|
2025-07-15 00:03:02 +08:00
|
|
|
|
func (p *JikepanAsyncV2Plugin) convertResults(items []JikepanItem) []model.SearchResult {
|
2025-07-12 19:53:44 +08:00
|
|
|
|
results := make([]model.SearchResult, 0, len(items))
|
|
|
|
|
|
|
|
|
|
|
|
for i, item := range items {
|
|
|
|
|
|
// 跳过没有链接的结果
|
|
|
|
|
|
if len(item.Links) == 0 {
|
|
|
|
|
|
continue
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 创建链接列表
|
|
|
|
|
|
links := make([]model.Link, 0, len(item.Links))
|
|
|
|
|
|
for _, link := range item.Links {
|
|
|
|
|
|
linkType := p.convertLinkType(link.Service)
|
|
|
|
|
|
|
|
|
|
|
|
// 特殊处理other类型,检查链接URL
|
|
|
|
|
|
if linkType == "others" && strings.Contains(strings.ToLower(link.Link), "drive.uc.cn") {
|
|
|
|
|
|
linkType = "uc"
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 跳过未知类型的链接(linkType为空)
|
|
|
|
|
|
if linkType == "" {
|
|
|
|
|
|
continue
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 创建链接
|
|
|
|
|
|
links = append(links, model.Link{
|
|
|
|
|
|
URL: link.Link,
|
|
|
|
|
|
Type: linkType,
|
|
|
|
|
|
Password: link.Pwd,
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 创建唯一ID:插件名-索引
|
|
|
|
|
|
uniqueID := fmt.Sprintf("jikepan-%d", i)
|
|
|
|
|
|
|
|
|
|
|
|
// 创建搜索结果
|
|
|
|
|
|
result := model.SearchResult{
|
|
|
|
|
|
UniqueID: uniqueID,
|
|
|
|
|
|
Title: item.Name,
|
2025-07-15 00:03:02 +08:00
|
|
|
|
Datetime: time.Time{}, // 使用零值而不是nil
|
2025-07-12 19:53:44 +08:00
|
|
|
|
Links: links,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
results = append(results, result)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return results
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// convertLinkType 将API的服务类型转换为标准链接类型
|
2025-07-15 00:03:02 +08:00
|
|
|
|
func (p *JikepanAsyncV2Plugin) convertLinkType(service string) string {
|
2025-07-12 19:53:44 +08:00
|
|
|
|
service = strings.ToLower(service)
|
|
|
|
|
|
|
|
|
|
|
|
switch service {
|
|
|
|
|
|
case "baidu":
|
|
|
|
|
|
return "baidu"
|
|
|
|
|
|
case "aliyun":
|
|
|
|
|
|
return "aliyun"
|
|
|
|
|
|
case "xunlei":
|
|
|
|
|
|
return "xunlei"
|
|
|
|
|
|
case "quark":
|
|
|
|
|
|
return "quark"
|
|
|
|
|
|
case "189cloud":
|
|
|
|
|
|
return "tianyi"
|
|
|
|
|
|
case "115":
|
|
|
|
|
|
return "115"
|
|
|
|
|
|
case "123":
|
|
|
|
|
|
return "123"
|
|
|
|
|
|
case "weiyun":
|
|
|
|
|
|
return "weiyun"
|
|
|
|
|
|
case "pikpak":
|
|
|
|
|
|
return "pikpak"
|
|
|
|
|
|
case "lanzou":
|
|
|
|
|
|
return "lanzou"
|
|
|
|
|
|
case "jianguoyun":
|
|
|
|
|
|
return "jianguoyun"
|
|
|
|
|
|
case "caiyun":
|
|
|
|
|
|
return "mobile"
|
|
|
|
|
|
case "chengtong":
|
|
|
|
|
|
return "chengtong"
|
|
|
|
|
|
case "ed2k":
|
|
|
|
|
|
return "ed2k"
|
|
|
|
|
|
case "magnet":
|
|
|
|
|
|
return "magnet"
|
|
|
|
|
|
case "unknown":
|
|
|
|
|
|
// 对于未知类型,返回空字符串,以便在后续处理中跳过
|
|
|
|
|
|
return ""
|
|
|
|
|
|
default:
|
|
|
|
|
|
return "others"
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// JikepanResponse API响应结构
|
|
|
|
|
|
type JikepanResponse struct {
|
2025-07-15 00:03:02 +08:00
|
|
|
|
Msg string `json:"msg"`
|
2025-07-12 19:53:44 +08:00
|
|
|
|
List []JikepanItem `json:"list"`
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// JikepanItem API响应中的单个结果项
|
|
|
|
|
|
type JikepanItem struct {
|
|
|
|
|
|
Name string `json:"name"`
|
|
|
|
|
|
Links []JikepanLink `json:"links"`
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-15 00:03:02 +08:00
|
|
|
|
// JikepanLink API响应中的链接信息
|
2025-07-12 19:53:44 +08:00
|
|
|
|
type JikepanLink struct {
|
|
|
|
|
|
Service string `json:"service"`
|
|
|
|
|
|
Link string `json:"link"`
|
|
|
|
|
|
Pwd string `json:"pwd,omitempty"`
|
|
|
|
|
|
}
|