Files
urldb/handlers/cks_handler.go

499 lines
13 KiB
Go
Raw Permalink Normal View History

2025-07-10 13:58:28 +08:00
package handlers
import (
2025-09-03 00:48:10 +08:00
"encoding/json"
2025-11-10 14:29:28 +08:00
"log"
2025-07-10 13:58:28 +08:00
"net/http"
"strconv"
2025-07-17 01:43:22 +08:00
"strings"
2025-07-10 13:58:28 +08:00
2025-07-18 09:42:07 +08:00
panutils "github.com/ctwj/urldb/common"
"github.com/ctwj/urldb/db/converter"
"github.com/ctwj/urldb/db/dto"
"github.com/ctwj/urldb/db/entity"
2025-07-10 13:58:28 +08:00
"github.com/gin-gonic/gin"
)
// GetCks 获取Cookie列表
func GetCks(c *gin.Context) {
cks, err := repoManager.CksRepository.FindAll()
if err != nil {
2025-07-11 17:45:16 +08:00
ErrorResponse(c, err.Error(), http.StatusInternalServerError)
2025-07-10 13:58:28 +08:00
return
}
2025-11-05 20:52:32 +08:00
// 使用新的逻辑创建 CksResponse
var responses []dto.CksResponse
for _, ck := range cks {
// 获取平台信息
var pan *dto.PanResponse
if ck.PanID != 0 {
panEntity, err := repoManager.PanRepository.FindByID(ck.PanID)
if err == nil && panEntity != nil {
pan = &dto.PanResponse{
ID: panEntity.ID,
Name: panEntity.Name,
Key: panEntity.Key,
Icon: panEntity.Icon,
Remark: panEntity.Remark,
}
}
}
// 统计转存资源数
count, err := repoManager.ResourceRepository.CountResourcesByCkID(ck.ID)
if err != nil {
count = 0 // 统计失败时设为0
}
response := dto.CksResponse{
ID: ck.ID,
PanID: ck.PanID,
Idx: ck.Idx,
Ck: ck.Ck,
IsValid: ck.IsValid,
Space: ck.Space,
LeftSpace: ck.LeftSpace,
UsedSpace: ck.UsedSpace,
Username: ck.Username,
VipStatus: ck.VipStatus,
ServiceType: ck.ServiceType,
Remark: ck.Remark,
TransferredCount: count,
Pan: pan,
}
responses = append(responses, response)
}
2025-07-11 17:45:16 +08:00
SuccessResponse(c, responses)
2025-07-10 13:58:28 +08:00
}
// CreateCks 创建Cookie
func CreateCks(c *gin.Context) {
var req dto.CreateCksRequest
if err := c.ShouldBindJSON(&req); err != nil {
2025-07-11 17:45:16 +08:00
ErrorResponse(c, err.Error(), http.StatusBadRequest)
2025-07-10 13:58:28 +08:00
return
}
2025-07-17 01:43:22 +08:00
// 获取平台信息以确定服务类型
pan, err := repoManager.PanRepository.FindByID(req.PanID)
if err != nil {
ErrorResponse(c, "平台不存在", http.StatusBadRequest)
return
}
// 根据平台名称确定服务类型
var serviceType panutils.ServiceType
switch pan.Name {
case "quark":
serviceType = panutils.Quark
case "alipan":
serviceType = panutils.Alipan
case "baidu":
serviceType = panutils.BaiduPan
case "uc":
serviceType = panutils.UC
2025-08-20 00:13:31 +08:00
case "xunlei":
serviceType = panutils.Xunlei
2025-07-17 01:43:22 +08:00
default:
ErrorResponse(c, "不支持的平台类型", http.StatusBadRequest)
return
}
// 创建网盘服务实例
factory := panutils.GetInstance()
service, err := factory.CreatePanServiceByType(serviceType, &panutils.PanConfig{})
if err != nil {
ErrorResponse(c, "创建网盘服务失败: "+err.Error(), http.StatusInternalServerError)
return
}
2025-09-03 00:48:10 +08:00
var cks *entity.Cks
2025-11-10 14:29:28 +08:00
// 迅雷网盘,使用账号密码登录
2025-09-03 00:48:10 +08:00
if serviceType == panutils.Xunlei {
2025-11-10 14:29:28 +08:00
// 解析账号密码信息
credentials, err := panutils.ParseCredentialsFromCk(req.Ck)
if err != nil {
ErrorResponse(c, "账号密码格式错误: "+err.Error(), http.StatusBadRequest)
return
}
// 验证账号密码
if credentials.Username == "" || credentials.Password == "" {
ErrorResponse(c, "请提供完整的账号和密码", http.StatusBadRequest)
return
}
var tokenData *panutils.XunleiTokenData
var username string
// 使用账号密码登录
2025-09-03 00:48:10 +08:00
xunleiService := service.(*panutils.XunleiPanService)
2025-11-10 14:29:28 +08:00
token, err := xunleiService.LoginWithCredentials(credentials.Username, credentials.Password)
2025-09-03 00:48:10 +08:00
if err != nil {
2025-11-10 14:29:28 +08:00
ErrorResponse(c, "账号密码登录失败: "+err.Error(), http.StatusBadRequest)
2025-09-03 00:48:10 +08:00
return
}
2025-11-10 14:29:28 +08:00
tokenData = &token
username = credentials.Username
// 构建extra数据
extra := panutils.XunleiExtraData{
2025-11-10 14:29:28 +08:00
Token: tokenData,
Captcha: &panutils.CaptchaData{},
}
2025-11-10 14:29:28 +08:00
// 如果有账号密码信息保存到extra中
if credentials.Username != "" && credentials.Password != "" {
extra.Credentials = credentials
}
extraStr, _ := json.Marshal(extra)
2025-09-03 00:48:10 +08:00
2025-11-10 14:29:28 +08:00
// 声明userInfo变量
var userInfo *panutils.UserInfo
// 设置CKSRepository以便获取用户信息
xunleiService.SetCKSRepository(repoManager.CksRepository, entity.Cks{})
// 获取用户信息
userInfo, err = xunleiService.GetUserInfo(nil)
if err != nil {
log.Printf("获取迅雷用户信息失败,使用默认值: %v", err)
// 如果获取失败,使用默认值
userInfo = &panutils.UserInfo{
Username: username,
VIPStatus: false,
ServiceType: "xunlei",
TotalSpace: 0,
UsedSpace: 0,
}
}
leftSpaceBytes := userInfo.TotalSpace - userInfo.UsedSpace
2025-09-03 00:48:10 +08:00
// 创建Cks实体
cks = &entity.Cks{
PanID: req.PanID,
Idx: req.Idx,
2025-11-10 14:29:28 +08:00
Ck: req.Ck, // 保持原始输入
IsValid: userInfo.VIPStatus, // 根据VIP状态设置有效性
Space: userInfo.TotalSpace,
LeftSpace: leftSpaceBytes,
UsedSpace: userInfo.UsedSpace,
Username: userInfo.Username,
VipStatus: userInfo.VIPStatus,
ServiceType: userInfo.ServiceType,
Extra: string(extraStr),
2025-09-03 00:48:10 +08:00
Remark: req.Remark,
}
} else {
// 获取用户信息
2025-09-03 23:39:26 +08:00
userInfo, err := service.GetUserInfo(&req.Ck)
2025-09-03 00:48:10 +08:00
if err != nil {
ErrorResponse(c, "无法获取用户信息,账号创建失败: "+err.Error(), http.StatusBadRequest)
return
}
2025-07-17 01:43:22 +08:00
2025-09-03 00:48:10 +08:00
leftSpaceBytes := userInfo.TotalSpace - userInfo.UsedSpace
2025-07-17 01:43:22 +08:00
2025-09-03 00:48:10 +08:00
// 创建Cks实体
cks = &entity.Cks{
PanID: req.PanID,
Idx: req.Idx,
Ck: req.Ck,
IsValid: userInfo.VIPStatus, // 根据VIP状态设置有效性
Space: userInfo.TotalSpace,
LeftSpace: leftSpaceBytes,
UsedSpace: userInfo.UsedSpace,
Username: userInfo.Username,
VipStatus: userInfo.VIPStatus,
ServiceType: userInfo.ServiceType,
Extra: userInfo.ExtraData,
Remark: req.Remark,
}
2025-07-10 13:58:28 +08:00
}
2025-07-17 01:43:22 +08:00
err = repoManager.CksRepository.Create(cks)
2025-07-10 13:58:28 +08:00
if err != nil {
2025-07-11 17:45:16 +08:00
ErrorResponse(c, err.Error(), http.StatusInternalServerError)
2025-07-10 13:58:28 +08:00
return
}
2025-07-11 17:45:16 +08:00
SuccessResponse(c, gin.H{
2025-07-17 01:43:22 +08:00
"message": "账号创建成功",
2025-07-11 17:45:16 +08:00
"cks": converter.ToCksResponse(cks),
2025-07-10 13:58:28 +08:00
})
}
2025-07-17 01:43:22 +08:00
// parseCapacityToBytes 将容量字符串转换为字节数
func parseCapacityToBytes(capacity string) int64 {
if capacity == "未知" || capacity == "" {
return 0
}
// 移除空格并转换为小写
capacity = strings.TrimSpace(strings.ToLower(capacity))
var multiplier int64 = 1
if strings.Contains(capacity, "gb") {
multiplier = 1024 * 1024 * 1024
capacity = strings.Replace(capacity, "gb", "", -1)
} else if strings.Contains(capacity, "mb") {
multiplier = 1024 * 1024
capacity = strings.Replace(capacity, "mb", "", -1)
} else if strings.Contains(capacity, "kb") {
multiplier = 1024
capacity = strings.Replace(capacity, "kb", "", -1)
} else if strings.Contains(capacity, "b") {
capacity = strings.Replace(capacity, "b", "", -1)
}
// 解析数字
capacity = strings.TrimSpace(capacity)
if capacity == "" {
return 0
}
// 尝试解析浮点数
if strings.Contains(capacity, ".") {
if val, err := strconv.ParseFloat(capacity, 64); err == nil {
return int64(val * float64(multiplier))
}
} else {
if val, err := strconv.ParseInt(capacity, 10, 64); err == nil {
return val * multiplier
}
}
return 0
}
2025-07-11 17:45:16 +08:00
// GetCksByID 根据ID获取Cookie详情
func GetCksByID(c *gin.Context) {
idStr := c.Param("id")
id, err := strconv.ParseUint(idStr, 10, 32)
if err != nil {
ErrorResponse(c, "无效的ID", http.StatusBadRequest)
return
}
cks, err := repoManager.CksRepository.FindByID(uint(id))
if err != nil {
ErrorResponse(c, "Cookie不存在", http.StatusNotFound)
return
}
response := converter.ToCksResponse(cks)
SuccessResponse(c, response)
}
2025-07-10 13:58:28 +08:00
// UpdateCks 更新Cookie
func UpdateCks(c *gin.Context) {
idStr := c.Param("id")
id, err := strconv.ParseUint(idStr, 10, 32)
if err != nil {
2025-07-11 17:45:16 +08:00
ErrorResponse(c, "无效的ID", http.StatusBadRequest)
2025-07-10 13:58:28 +08:00
return
}
var req dto.UpdateCksRequest
if err := c.ShouldBindJSON(&req); err != nil {
2025-07-11 17:45:16 +08:00
ErrorResponse(c, err.Error(), http.StatusBadRequest)
2025-07-10 13:58:28 +08:00
return
}
cks, err := repoManager.CksRepository.FindByID(uint(id))
if err != nil {
2025-07-11 17:45:16 +08:00
ErrorResponse(c, "Cookie不存在", http.StatusNotFound)
2025-07-10 13:58:28 +08:00
return
}
if req.PanID != 0 {
cks.PanID = req.PanID
}
2025-07-11 17:45:16 +08:00
if req.Idx != 0 {
cks.Idx = req.Idx
}
2025-07-10 13:58:28 +08:00
if req.Ck != "" {
cks.Ck = req.Ck
}
// 对于 bool 类型,我们需要检查请求中是否包含该字段
// 由于 Go 的 JSON 解析,如果字段存在且为 false也会被正确解析
2025-07-11 10:01:48 +08:00
cks.IsValid = req.IsValid
2025-07-11 17:45:16 +08:00
if req.LeftSpace != 0 {
cks.LeftSpace = req.LeftSpace
}
2025-07-17 01:43:22 +08:00
if req.UsedSpace != 0 {
cks.UsedSpace = req.UsedSpace
}
if req.Username != "" {
cks.Username = req.Username
}
cks.VipStatus = req.VipStatus
if req.ServiceType != "" {
cks.ServiceType = req.ServiceType
}
2025-07-10 13:58:28 +08:00
if req.Remark != "" {
cks.Remark = req.Remark
}
// 使用专门的方法更新,确保更新所有字段包括零值
err = repoManager.CksRepository.UpdateWithAllFields(cks)
2025-07-10 13:58:28 +08:00
if err != nil {
2025-07-11 17:45:16 +08:00
ErrorResponse(c, err.Error(), http.StatusInternalServerError)
2025-07-10 13:58:28 +08:00
return
}
2025-07-11 17:45:16 +08:00
SuccessResponse(c, gin.H{"message": "Cookie更新成功"})
2025-07-10 13:58:28 +08:00
}
// DeleteCks 删除Cookie
func DeleteCks(c *gin.Context) {
idStr := c.Param("id")
id, err := strconv.ParseUint(idStr, 10, 32)
if err != nil {
2025-07-11 17:45:16 +08:00
ErrorResponse(c, "无效的ID", http.StatusBadRequest)
2025-07-10 13:58:28 +08:00
return
}
err = repoManager.CksRepository.Delete(uint(id))
if err != nil {
2025-07-11 17:45:16 +08:00
ErrorResponse(c, err.Error(), http.StatusInternalServerError)
2025-07-10 13:58:28 +08:00
return
}
2025-07-11 17:45:16 +08:00
SuccessResponse(c, gin.H{"message": "Cookie删除成功"})
2025-07-10 13:58:28 +08:00
}
2025-07-11 17:45:16 +08:00
// GetCksByID 根据ID获取Cookie详情使用全局repoManager
func GetCksByIDGlobal(c *gin.Context) {
2025-07-10 13:58:28 +08:00
idStr := c.Param("id")
id, err := strconv.ParseUint(idStr, 10, 32)
if err != nil {
2025-07-11 17:45:16 +08:00
ErrorResponse(c, "无效的ID", http.StatusBadRequest)
2025-07-10 13:58:28 +08:00
return
}
cks, err := repoManager.CksRepository.FindByID(uint(id))
if err != nil {
2025-07-11 17:45:16 +08:00
ErrorResponse(c, "Cookie不存在", http.StatusNotFound)
2025-07-10 13:58:28 +08:00
return
}
response := converter.ToCksResponse(cks)
2025-07-11 17:45:16 +08:00
SuccessResponse(c, response)
2025-07-10 13:58:28 +08:00
}
2025-07-17 01:43:22 +08:00
// RefreshCapacity 刷新账号容量信息
func RefreshCapacity(c *gin.Context) {
idStr := c.Param("id")
id, err := strconv.ParseUint(idStr, 10, 32)
if err != nil {
ErrorResponse(c, "无效的ID", http.StatusBadRequest)
return
}
// 获取账号信息
cks, err := repoManager.CksRepository.FindByID(uint(id))
if err != nil {
ErrorResponse(c, "账号不存在", http.StatusNotFound)
return
}
// 获取平台信息以确定服务类型
pan, err := repoManager.PanRepository.FindByID(cks.PanID)
if err != nil {
ErrorResponse(c, "平台不存在", http.StatusBadRequest)
return
}
// 根据平台名称确定服务类型
var serviceType panutils.ServiceType
switch pan.Name {
case "quark":
serviceType = panutils.Quark
case "alipan":
serviceType = panutils.Alipan
case "baidu":
serviceType = panutils.BaiduPan
case "uc":
serviceType = panutils.UC
2025-09-03 15:44:47 +08:00
case "xunlei":
serviceType = panutils.Xunlei
2025-07-17 01:43:22 +08:00
default:
ErrorResponse(c, "不支持的平台类型", http.StatusBadRequest)
return
}
// 创建网盘服务实例
factory := panutils.GetInstance()
service, err := factory.CreatePanServiceByType(serviceType, &panutils.PanConfig{})
if err != nil {
ErrorResponse(c, "创建网盘服务失败: "+err.Error(), http.StatusInternalServerError)
return
}
2025-09-03 23:39:26 +08:00
var userInfo *panutils.UserInfo
service.SetCKSRepository(repoManager.CksRepository, *cks) // 迅雷需要初始化 token 后才能获取,
2025-11-10 14:29:28 +08:00
// 根据服务类型调用不同的GetUserInfo方法
switch s := service.(type) {
case *panutils.XunleiPanService:
// 迅雷网盘使用存储在extra中的token不需要传递ck参数
userInfo, err = s.GetUserInfo(nil)
default:
// 其他网盘使用ck参数
userInfo, err = service.GetUserInfo(&cks.Ck)
}
2025-09-03 23:39:26 +08:00
if err != nil {
ErrorResponse(c, "无法获取用户信息,刷新失败: "+err.Error(), http.StatusBadRequest)
return
}
leftSpaceBytes := userInfo.TotalSpace - userInfo.UsedSpace
2025-07-17 01:43:22 +08:00
2025-09-03 23:39:26 +08:00
// 更新账号信息
cks.Username = userInfo.Username
cks.VipStatus = userInfo.VIPStatus
cks.ServiceType = userInfo.ServiceType
cks.Space = userInfo.TotalSpace
cks.LeftSpace = leftSpaceBytes
cks.UsedSpace = userInfo.UsedSpace
// cks.IsValid = userInfo.VIPStatus // 根据VIP状态更新有效性
2025-07-17 01:43:22 +08:00
2025-09-03 23:39:26 +08:00
err = repoManager.CksRepository.UpdateWithAllFields(cks)
if err != nil {
ErrorResponse(c, err.Error(), http.StatusInternalServerError)
return
2025-07-17 01:43:22 +08:00
}
SuccessResponse(c, gin.H{
"message": "容量信息刷新成功",
"cks": converter.ToCksResponse(cks),
})
}
2025-11-05 20:52:32 +08:00
// DeleteRelatedResources 删除关联资源
func DeleteRelatedResources(c *gin.Context) {
idStr := c.Param("id")
id, err := strconv.ParseUint(idStr, 10, 32)
if err != nil {
ErrorResponse(c, "无效的ID", http.StatusBadRequest)
return
}
// 调用资源库删除关联资源
affectedRows, err := repoManager.ResourceRepository.DeleteRelatedResources(uint(id))
if err != nil {
ErrorResponse(c, "删除关联资源失败: "+err.Error(), http.StatusInternalServerError)
return
}
SuccessResponse(c, gin.H{
"message": "关联资源删除成功",
"affected_rows": affectedRows,
})
}