mirror of
https://github.com/ctwj/urldb.git
synced 2025-11-25 03:15:04 +08:00
update: pan
This commit is contained in:
@@ -90,15 +90,6 @@ func (q *QuarkPanService) Transfer(shareID string) (*TransferResult, error) {
|
||||
return ErrorResult(fmt.Sprintf("获取stoken失败: %v", err)), nil
|
||||
}
|
||||
|
||||
if config.IsType == 1 {
|
||||
// 直接返回资源信息
|
||||
return SuccessResult("检验成功", map[string]interface{}{
|
||||
"title": stokenResult.Title,
|
||||
"shareUrl": config.URL,
|
||||
"stoken": stokenResult.Stoken,
|
||||
}), nil
|
||||
}
|
||||
|
||||
stoken = strings.ReplaceAll(stokenResult.Stoken, " ", "+")
|
||||
} else {
|
||||
stoken = strings.ReplaceAll(config.Stoken, " ", "+")
|
||||
@@ -110,6 +101,42 @@ func (q *QuarkPanService) Transfer(shareID string) (*TransferResult, error) {
|
||||
return ErrorResult(fmt.Sprintf("获取分享详情失败: %v", err)), nil
|
||||
}
|
||||
|
||||
if config.IsType == 1 {
|
||||
// 遍历 资源目录结构
|
||||
for _, item := range shareResult.List {
|
||||
// 获取文件信息
|
||||
fileList, err := q.getDirFile(item.Fid)
|
||||
if err != nil {
|
||||
log.Printf("获取目录文件失败: %v", err)
|
||||
continue
|
||||
}
|
||||
|
||||
// 处理文件列表
|
||||
if fileList != nil {
|
||||
log.Printf("目录 %s 包含 %d 个文件/文件夹", item.Fid, len(fileList))
|
||||
|
||||
// 遍历所有文件,可以在这里添加具体的处理逻辑
|
||||
for _, file := range fileList {
|
||||
if fileName, ok := file["file_name"].(string); ok {
|
||||
if fileType, ok := file["file_type"].(float64); ok {
|
||||
fileTypeStr := "文件"
|
||||
if fileType == 1 {
|
||||
fileTypeStr = "目录"
|
||||
}
|
||||
log.Printf(" - %s (%s)", fileName, fileTypeStr)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 直接返回资源信息
|
||||
return SuccessResult("检验成功", map[string]interface{}{
|
||||
"title": shareResult.Share.Title,
|
||||
"shareUrl": config.URL,
|
||||
}), nil
|
||||
}
|
||||
|
||||
// 提取文件信息
|
||||
fidList := make([]string, 0)
|
||||
fidTokenList := make([]string, 0)
|
||||
@@ -280,18 +307,23 @@ func (q *QuarkPanService) getStoken(shareID string) (*StokenResult, error) {
|
||||
|
||||
// getShare 获取分享详情
|
||||
func (q *QuarkPanService) getShare(shareID, stoken string) (*ShareResult, error) {
|
||||
data := map[string]interface{}{
|
||||
"pwd_id": shareID,
|
||||
"stoken": stoken,
|
||||
}
|
||||
|
||||
queryParams := map[string]string{
|
||||
"pr": "ucpro",
|
||||
"fr": "pc",
|
||||
"uc_param_str": "",
|
||||
"pr": "ucpro",
|
||||
"fr": "pc",
|
||||
"uc_param_str": "",
|
||||
"pwd_id": shareID,
|
||||
"stoken": stoken,
|
||||
"pdir_fid": "0",
|
||||
"force": "0",
|
||||
"_page": "1",
|
||||
"_size": "100",
|
||||
"_fetch_banner": "1",
|
||||
"_fetch_share": "1",
|
||||
"_fetch_total": "1",
|
||||
"_sort": "file_type:asc,updated_at:desc",
|
||||
}
|
||||
|
||||
respData, err := q.HTTPPost("https://drive-pc.quark.cn/1/clouddrive/share/sharepage/detail", data, queryParams)
|
||||
respData, err := q.HTTPGet("https://drive-pc.quark.cn/1/clouddrive/share/sharepage/detail", queryParams)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -481,6 +513,67 @@ func (q *QuarkPanService) deleteAdFiles(pdirFid string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// getDirFile 获取指定文件夹的文件列表
|
||||
func (q *QuarkPanService) getDirFile(pdirFid string) ([]map[string]interface{}, error) {
|
||||
log.Printf("正在遍历父文件夹: %s", pdirFid)
|
||||
|
||||
queryParams := map[string]string{
|
||||
"pr": "ucpro",
|
||||
"fr": "pc",
|
||||
"uc_param_str": "",
|
||||
"pdir_fid": pdirFid,
|
||||
"_page": "1",
|
||||
"_size": "50",
|
||||
"_fetch_total": "1",
|
||||
"_fetch_sub_dirs": "0",
|
||||
"_sort": "updated_at:desc",
|
||||
}
|
||||
|
||||
respData, err := q.HTTPGet("https://drive-pc.quark.cn/1/clouddrive/file/sort", queryParams)
|
||||
if err != nil {
|
||||
log.Printf("获取目录文件失败: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var response struct {
|
||||
Status int `json:"status"`
|
||||
Message string `json:"message"`
|
||||
Data struct {
|
||||
List []map[string]interface{} `json:"list"`
|
||||
} `json:"data"`
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(respData, &response); err != nil {
|
||||
log.Printf("解析目录文件响应失败: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if response.Status != 200 {
|
||||
return nil, fmt.Errorf(response.Message)
|
||||
}
|
||||
|
||||
// 递归处理子目录
|
||||
var allFiles []map[string]interface{}
|
||||
for _, item := range response.Data.List {
|
||||
// 添加当前文件/目录
|
||||
allFiles = append(allFiles, item)
|
||||
|
||||
// 如果是目录,递归获取子目录内容
|
||||
if fileType, ok := item["file_type"].(float64); ok && fileType == 1 { // 1表示目录
|
||||
if fid, ok := item["fid"].(string); ok {
|
||||
subFiles, err := q.getDirFile(fid)
|
||||
if err != nil {
|
||||
log.Printf("获取子目录 %s 失败: %v", fid, err)
|
||||
continue
|
||||
}
|
||||
allFiles = append(allFiles, subFiles...)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return allFiles, nil
|
||||
}
|
||||
|
||||
// 定义各种结果结构体
|
||||
type StokenResult struct {
|
||||
Stoken string `json:"stoken"`
|
||||
@@ -1,4 +1,4 @@
|
||||
package utils
|
||||
package common
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
166
doc/QUARK_GETSHARE_FIX.md
Normal file
166
doc/QUARK_GETSHARE_FIX.md
Normal file
@@ -0,0 +1,166 @@
|
||||
# 夸克网盘 getShare 方法修复
|
||||
|
||||
## 问题描述
|
||||
|
||||
在夸克网盘的 `getShare` 函数中遇到了 HTTP 405 错误:
|
||||
|
||||
```
|
||||
HTTP请求失败: 405, {"timestamp":1752368941648,"status":405,"error":"Method Not Allowed","exception":"org.springframework.web.HttpRequestMethodNotSupportedException","message":"Request method 'POST' not supported","path":"/1/clouddrive/share/sharepage/detail"}
|
||||
```
|
||||
|
||||
## 问题分析
|
||||
|
||||
### 错误原因
|
||||
- 当前Go代码使用 `HTTPPost` 方法请求 `/1/clouddrive/share/sharepage/detail` 接口
|
||||
- 但服务器返回 405 错误,表示不支持 POST 方法
|
||||
- 需要改为 GET 请求
|
||||
|
||||
### 对比原始PHP代码
|
||||
通过对比 `demo/pan/QuarkPan.php` 中的 `getShare` 方法:
|
||||
|
||||
```php
|
||||
public function getShare($pwd_id,$stoken)
|
||||
{
|
||||
$urlData = array();
|
||||
$queryParams = [
|
||||
"pr" => "ucpro",
|
||||
"fr" => "pc",
|
||||
"uc_param_str" => "",
|
||||
"pwd_id" => $pwd_id,
|
||||
"stoken" => $stoken,
|
||||
"pdir_fid" => "0",
|
||||
"force" => "0",
|
||||
"_page" => "1",
|
||||
"_size" => "100",
|
||||
"_fetch_banner" => "1",
|
||||
"_fetch_share" => "1",
|
||||
"_fetch_total" => "1",
|
||||
"_sort" => "file_type:asc,updated_at:desc"
|
||||
];
|
||||
return $this->executeApiRequest(
|
||||
"https://drive-pc.quark.cn/1/clouddrive/share/sharepage/detail",
|
||||
"GET", // 使用 GET 方法
|
||||
$urlData,
|
||||
$queryParams
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
## 修复方案
|
||||
|
||||
### 修复前的代码
|
||||
```go
|
||||
// 修复前:使用 POST 请求
|
||||
func (q *QuarkPanService) getShare(shareID, stoken string) (*ShareResult, error) {
|
||||
data := map[string]interface{}{
|
||||
"pwd_id": shareID,
|
||||
"stoken": stoken,
|
||||
}
|
||||
|
||||
queryParams := map[string]string{
|
||||
"pr": "ucpro",
|
||||
"fr": "pc",
|
||||
"uc_param_str": "",
|
||||
}
|
||||
|
||||
respData, err := q.HTTPPost("https://drive-pc.quark.cn/1/clouddrive/share/sharepage/detail", data, queryParams)
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
### 修复后的代码
|
||||
```go
|
||||
// 修复后:使用 GET 请求,参数放在 URL 中
|
||||
func (q *QuarkPanService) getShare(shareID, stoken string) (*ShareResult, error) {
|
||||
queryParams := map[string]string{
|
||||
"pr": "ucpro",
|
||||
"fr": "pc",
|
||||
"uc_param_str": "",
|
||||
"pwd_id": shareID,
|
||||
"stoken": stoken,
|
||||
"pdir_fid": "0",
|
||||
"force": "0",
|
||||
"_page": "1",
|
||||
"_size": "100",
|
||||
"_fetch_banner": "1",
|
||||
"_fetch_share": "1",
|
||||
"_fetch_total": "1",
|
||||
"_sort": "file_type:asc,updated_at:desc",
|
||||
}
|
||||
|
||||
respData, err := q.HTTPGet("https://drive-pc.quark.cn/1/clouddrive/share/sharepage/detail", queryParams)
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
## 修复内容
|
||||
|
||||
### 1. 请求方法修改
|
||||
- **从 POST 改为 GET**:`HTTPPost` → `HTTPGet`
|
||||
- **参数传递方式**:从请求体改为 URL 查询参数
|
||||
|
||||
### 2. 参数结构调整
|
||||
- **移除请求体数据**:不再使用 `data` 参数
|
||||
- **添加完整查询参数**:按照PHP代码添加所有必要的查询参数
|
||||
- **参数顺序**:保持与PHP代码一致的参数顺序
|
||||
|
||||
### 3. 参数说明
|
||||
| 参数 | 说明 | 值 |
|
||||
|------|------|-----|
|
||||
| `pr` | 产品标识 | `ucpro` |
|
||||
| `fr` | 来源标识 | `pc` |
|
||||
| `uc_param_str` | UC参数 | 空字符串 |
|
||||
| `pwd_id` | 分享ID | 从URL提取 |
|
||||
| `stoken` | 安全令牌 | 从getStoken获取 |
|
||||
| `pdir_fid` | 父目录ID | `0` |
|
||||
| `force` | 强制标志 | `0` |
|
||||
| `_page` | 页码 | `1` |
|
||||
| `_size` | 页面大小 | `100` |
|
||||
| `_fetch_banner` | 获取横幅 | `1` |
|
||||
| `_fetch_share` | 获取分享信息 | `1` |
|
||||
| `_fetch_total` | 获取总数 | `1` |
|
||||
| `_sort` | 排序方式 | `file_type:asc,updated_at:desc` |
|
||||
|
||||
## 验证结果
|
||||
|
||||
### 编译测试
|
||||
```bash
|
||||
go build -o res_db .
|
||||
# ✅ 编译成功
|
||||
```
|
||||
|
||||
### 功能测试
|
||||
```bash
|
||||
go test ./utils/pan -v
|
||||
# ✅ 所有测试通过
|
||||
```
|
||||
|
||||
### 预期效果
|
||||
- **解决 405 错误**:使用正确的 GET 请求方法
|
||||
- **保持功能完整**:所有参数都正确传递
|
||||
- **兼容性良好**:与原始PHP代码行为一致
|
||||
|
||||
## 经验总结
|
||||
|
||||
### 1. API 兼容性
|
||||
- 在翻译代码时,需要仔细对比原始实现的请求方法
|
||||
- 不同语言的HTTP客户端可能有不同的默认行为
|
||||
- 需要确保请求方法、参数位置、参数名称都完全一致
|
||||
|
||||
### 2. 错误排查
|
||||
- HTTP 405 错误通常表示请求方法不正确
|
||||
- 对比原始代码是排查此类问题的最佳方法
|
||||
- 需要检查请求方法、URL、参数等多个方面
|
||||
|
||||
### 3. 最佳实践
|
||||
- **保持一致性**:与原始实现保持完全一致
|
||||
- **完整参数**:不要遗漏任何必要的参数
|
||||
- **测试验证**:修复后要进行充分的测试
|
||||
|
||||
## 相关文件
|
||||
|
||||
- `utils/pan/quark_pan.go` - 修复的文件
|
||||
- `demo/pan/QuarkPan.php` - 原始PHP实现参考
|
||||
- `utils/pan/base_pan.go` - 基础HTTP方法实现
|
||||
|
||||
这次修复确保了夸克网盘的 `getShare` 方法与原始PHP实现完全一致,解决了HTTP 405错误问题。
|
||||
@@ -2,9 +2,10 @@ package utils
|
||||
|
||||
import (
|
||||
"log"
|
||||
panutils "res_db/common"
|
||||
commonutils "res_db/common/utils"
|
||||
"res_db/db/entity"
|
||||
"res_db/db/repo"
|
||||
panutils "res_db/utils/pan"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
@@ -315,11 +316,23 @@ func (s *Scheduler) convertReadyResourceToResource(readyResource entity.ReadyRes
|
||||
|
||||
log.Printf("检测到服务类型: %s, 分享ID: %s", serviceType.String(), shareID)
|
||||
|
||||
// 不是夸克,直接保存,
|
||||
if serviceType != panutils.Quark {
|
||||
// 检测是否有效
|
||||
checkResult, _ := commonutils.CheckURL(readyResource.URL)
|
||||
if !checkResult.Status {
|
||||
log.Printf("链接无效: %s", readyResource.URL)
|
||||
return nil
|
||||
}
|
||||
|
||||
// 入库
|
||||
}
|
||||
|
||||
// 准备配置
|
||||
config := &panutils.PanConfig{
|
||||
URL: readyResource.URL,
|
||||
Code: "", // 可以从readyResource中获取
|
||||
IsType: 0, // 转存并分享后的资源信息
|
||||
IsType: 1, // 转存并分享后的资源信息 0 转存后分享, 1 只获取基本信息
|
||||
ExpiredType: 1, // 永久分享
|
||||
AdFid: "",
|
||||
Stoken: "",
|
||||
@@ -333,45 +346,45 @@ func (s *Scheduler) convertReadyResourceToResource(readyResource entity.ReadyRes
|
||||
}
|
||||
|
||||
// 阿里云盘特殊处理:检查URL有效性
|
||||
if serviceType == panutils.Alipan {
|
||||
checkResult, _ := CheckURL(readyResource.URL)
|
||||
if !checkResult.Status {
|
||||
log.Printf("阿里云盘链接无效: %s", readyResource.URL)
|
||||
return nil
|
||||
}
|
||||
// if serviceType == panutils.Alipan {
|
||||
// checkResult, _ := CheckURL(readyResource.URL)
|
||||
// if !checkResult.Status {
|
||||
// log.Printf("阿里云盘链接无效: %s", readyResource.URL)
|
||||
// return nil
|
||||
// }
|
||||
|
||||
// 如果有标题,直接创建资源
|
||||
if readyResource.Title != nil && *readyResource.Title != "" {
|
||||
resource := &entity.Resource{
|
||||
Title: *readyResource.Title,
|
||||
Description: readyResource.Description,
|
||||
URL: readyResource.URL,
|
||||
PanID: s.determinePanID(readyResource.URL),
|
||||
IsValid: true,
|
||||
IsPublic: true,
|
||||
}
|
||||
// // 如果有标题,直接创建资源
|
||||
// if readyResource.Title != nil && *readyResource.Title != "" {
|
||||
// resource := &entity.Resource{
|
||||
// Title: *readyResource.Title,
|
||||
// Description: readyResource.Description,
|
||||
// URL: readyResource.URL,
|
||||
// PanID: s.determinePanID(readyResource.URL),
|
||||
// IsValid: true,
|
||||
// IsPublic: true,
|
||||
// }
|
||||
|
||||
// 如果有分类信息,尝试查找或创建分类
|
||||
if readyResource.Category != "" {
|
||||
categoryID, err := s.getOrCreateCategory(readyResource.Category)
|
||||
if err == nil {
|
||||
resource.CategoryID = &categoryID
|
||||
}
|
||||
}
|
||||
// // 如果有分类信息,尝试查找或创建分类
|
||||
// if readyResource.Category != "" {
|
||||
// categoryID, err := s.getOrCreateCategory(readyResource.Category)
|
||||
// if err == nil {
|
||||
// resource.CategoryID = &categoryID
|
||||
// }
|
||||
// }
|
||||
|
||||
return s.resourceRepo.Create(resource)
|
||||
}
|
||||
}
|
||||
// return s.resourceRepo.Create(resource)
|
||||
// }
|
||||
// }
|
||||
|
||||
// 统一处理:尝试转存获取标题
|
||||
result, err := panService.Transfer(shareID)
|
||||
if err != nil {
|
||||
log.Printf("网盘转存失败: %v", err)
|
||||
log.Printf("网盘信息获取失败: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
if !result.Success {
|
||||
log.Printf("网盘转存失败: %s", result.Message)
|
||||
log.Printf("网盘信息获取失败: %s", result.Message)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user