plugin/qqpd/README.md
QQPD是PanSou的QQ频道搜索插件,支持多用户登录QQ频道并配置频道列表,在搜索时自动聚合所有用户的频道资源。
cd /Users/macbookpro/Desktop/fish2018/pansou
ENABLED_PLUGINS=qqpd go run main.go
# 或者编译后运行
go build -o pansou main.go
ENABLED_PLUGINS=qqpd ./pansou
浏览器打开:
http://localhost:8888/qqpd/你的QQ号
示例:
http://localhost:8888/qqpd/1234567
系统会自动:
http://localhost:8888/qqpd/{hash}📌 提示:请收藏hash后的URL(包含你的专属hash),方便下次访问。
在"频道管理"区域输入频道号,每行一个:
pd97631607
languan8K115
m250319e25
支持格式:
pd97631607https://pd.qq.com/g/pd97631607点击"保存频道配置"按钮。
在PanSou主页搜索框输入关键词,系统会自动聚合所有用户的QQ频道结果!
# 通过API搜索
curl "http://localhost:8888/api/search?kw=遮天"
# 只搜索插件(包括qqpd)
curl "http://localhost:8888/api/search?kw=遮天&src=plugin"
所有操作通过统一的POST接口:
POST /qqpd/{hash}
Content-Type: application/json
{
"action": "操作类型",
...其他参数
}
| Action | 说明 | 需要登录 | 前端调用时机 |
|---|---|---|---|
get_status | 获取状态 | ❌ | 每3秒自动调用 |
refresh_qrcode | 刷新二维码 | ❌ | 用户点击刷新按钮 |
check_login | 检查登录状态 | ❌ | 未登录时每2秒调用 |
logout | 退出登录 | ✅ | 用户点击退出按钮 |
set_channels | 设置频道列表 | ✅ | 用户点击保存按钮 |
test_search | 测试搜索 | ✅ | 用户点击搜索按钮 |
作用:获取当前用户的登录状态、频道配置等信息
请求:
curl -X POST "http://localhost:8888/qqpd/{hash}" \
-H "Content-Type: application/json" \
-d '{"action": "get_status"}'
成功响应(已登录):
{
"success": true,
"message": "获取成功",
"data": {
"hash": "1dd868cc...",
"logged_in": true,
"status": "active",
"qq_masked": "1851****32",
"login_time": "2025-10-24 12:00:00",
"expire_time": "2035-10-24 12:00:00",
"expires_in_days": 3650,
"channels": ["pd97631607", "kuake12345"],
"channel_count": 2,
"qrcode_base64": ""
}
}
成功响应(未登录):
{
"success": true,
"message": "获取成功",
"data": {
"hash": "1dd868cc...",
"logged_in": false,
"status": "pending",
"qq_masked": "",
"channels": [],
"channel_count": 0,
"qrcode_base64": "data:image/png;base64,iVBORw0KGgo..." // Base64二维码
}
}
作用:强制生成新的二维码(当二维码过期时)
请求:
curl -X POST "http://localhost:8888/qqpd/{hash}" \
-H "Content-Type: application/json" \
-d '{"action": "refresh_qrcode"}'
成功响应:
{
"success": true,
"message": "二维码已刷新",
"data": {
"qrcode_base64": "data:image/png;base64,iVBORw0KGgo..."
}
}
说明:
作用:检查二维码是否被扫描,登录是否成功(扫码后轮询调用)
请求:
curl -X POST "http://localhost:8888/qqpd/{hash}" \
-H "Content-Type: application/json" \
-d '{"action": "check_login"}'
响应(等待扫码):
{
"success": true,
"message": "等待扫码",
"data": {
"login_status": "waiting"
}
}
响应(登录成功):
{
"success": true,
"message": "登录成功",
"data": {
"login_status": "success",
"qq_masked": "1851****32"
}
}
响应(二维码过期):
{
"success": false,
"message": "二维码已失效,请刷新"
}
说明:
作用:清除Cookie,退出登录状态
请求:
curl -X POST "http://localhost:8888/qqpd/{hash}" \
-H "Content-Type: application/json" \
-d '{"action": "logout"}'
成功响应:
{
"success": true,
"message": "已退出登录",
"data": {
"status": "pending"
}
}
作用:配置或更新频道列表(覆盖式更新)
请求:
curl -X POST "http://localhost:8888/qqpd/{hash}" \
-H "Content-Type: application/json" \
-d '{
"action": "set_channels",
"channels": ["pd97631607", "kuake12345", "https://pd.qq.com/g/languan8K115"]
}'
成功响应:
{
"success": true,
"message": "频道列表已更新",
"data": {
"channels": ["pd97631607", "kuake12345", "languan8K115"],
"channel_count": 3,
"invalid_channels": [],
"guild_ids_cached": 3
}
}
说明:
作用:在管理页面测试搜索功能
请求:
curl -X POST "http://localhost:8888/qqpd/{hash}" \
-H "Content-Type: application/json" \
-d '{
"action": "test_search",
"keyword": "遮天",
"max_results": 10
}'
参数:
keyword(必需):搜索关键词max_results(可选):最大返回数量,默认10成功响应:
{
"success": true,
"message": "找到 5 条结果",
"data": {
"keyword": "遮天",
"total_results": 5,
"channels_searched": ["pd97631607", "kuake12345", "languan8K115"],
"results": [
{
"unique_id": "qqpd-pd97631607-0",
"title": "遮天 (2023) 臻彩4K.更新至109集",
"links": [
{
"type": "quark",
"url": "https://pan.quark.cn/s/779d98f49e88",
"password": ""
}
]
},
...
]
}
}
# Hash Salt(推荐自定义,增强安全性)
export QQPD_HASH_SALT="your-custom-salt-here"
# Cookie加密密钥(32字节,推荐自定义)
export QQPD_ENCRYPTION_KEY="your-32-byte-key-here!!!!!!!!!!"
在 qqpd.go 第33-37行修改:
const (
MaxConcurrentUsers = 10 // 最多使用的用户数(搜索时)
MaxConcurrentChannels = 50 // 最大并发频道数
KeepAliveInterval = 3 * time.Minute // Session保活间隔
DebugLog = false // 调试日志开关
)
参数说明:
| 参数 | 默认值 | 说明 | 建议 |
|---|---|---|---|
MaxConcurrentUsers | 10 | 单次搜索最多使用的用户数 | 10-20足够 |
MaxConcurrentChannels | 50 | 最大并发频道数 | 50-100 |
KeepAliveInterval | 3分钟 | Session保活间隔 | 2-5分钟 |
DebugLog | false | 是否开启调试日志 | 生产环境false |
cache/qqpd_users/{hash}.json
{
"hash": "1dd868cc97f5540db170bb3208a4ad737cd7aea3e8df85535178dcbacfa46300",
"qq_masked": "123**67",
"cookie": "p_skey=xxx; uin=xxx; ...",
"status": "active",
"channels": ["pd97631607", "kuake12345", "languan8K115"],
"channel_guild_ids": {
"pd97631607": "592843764045681811",
"kuake12345": "987654321098765432",
"languan8K115": "612109904026776189"
},
"created_at": "2025-10-24T12:00:00+08:00",
"login_at": "2025-10-24T12:05:00+08:00",
"expire_at": "2035-10-24T12:05:00+08:00",
"last_access_at": "2025-10-24T13:00:00+08:00"
}
字段说明:
hash: 用户唯一标识(SHA256,不可逆推QQ号)qq_masked: 脱敏QQ号(如1851****32)cookie: QQ登录Cookie(明文存储,建议配置加密)status: 用户状态(pending/active/expired)channels: 频道号列表channel_guild_ids: 频道号→guild_id映射(性能优化缓存)expire_at: Cookie过期时间QQPD_ENCRYPTION_KEY定期清理任务(每24小时):
expired且30天未访问的用户expired问题:QQ频道的Cookie会在2天左右失效,导致搜索失败。
解决方案:自动保活机制
插件启动后:
↓ 延迟3分钟
↓
定期执行保活 (每3分钟):
↓
遍历所有active用户:
↓ 异步执行
访问 https://pd.qq.com/ (带Cookie)
↓
刷新服务器端session
↓
Cookie保持活跃状态 ✅
工作原理:
日志示例(DebugLog=true时):
[QQPD] 💓 Session保活: 已为 2 个用户执行保活任务
[QQPD] 💓 Session保活成功: 1851****32 (状态码: 200)
[QQPD] 💓 Session保活成功: 1234****56 (状态码: 200)
配置建议:
场景:多个用户各自配置不同的频道
用户A (QQ: 111111111)
↓
配置频道: [频道1, 频道2, 频道3]
用户B (QQ: 222222222)
↓
配置频道: [频道2, 频道4, 频道5]
用户C (QQ: 333333333)
↓
配置频道: [频道3, 频道5, 频道6]
搜索时:
↓
去重后的频道: [频道1, 频道2, 频道3, 频道4, 频道5, 频道6]
↓
负载均衡分配:
- 用户A: 搜索频道1, 频道4
- 用户B: 搜索频道2, 频道5
- 用户C: 搜索频道3, 频道6
性能提升:
首次保存频道:
pd97631607 → 访问 https://pd.qq.com/g/pd97631607
→ 提取 guild_id: 592843764045681811
→ 缓存到JSON
搜索时:
pd97631607 → 从内存读取 guild_id: 592843764045681811
→ 0网络请求 ⚡
→ 直接调用搜索API
效果:
用户A配置: [频道1, 频道2, 频道3]
用户B配置: [频道2, 频道3, 频道4]
去重后:
频道1 → 分配给用户A
频道2 → 分配给用户A(负载均衡)
频道3 → 分配给用户B(负载均衡)
频道4 → 分配给用户B
任务分配算法:
for each 频道:
选择当前任务数最少的用户来执行
效果:
- 避免单用户请求过多被限流
- 任务均匀分配
- 提高成功率