Files
urldb/handlers/cks_handler.go
2025-11-05 20:52:32 +08:00

447 lines
11 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package handlers
import (
"encoding/json"
"net/http"
"strconv"
"strings"
panutils "github.com/ctwj/urldb/common"
"github.com/ctwj/urldb/db/converter"
"github.com/ctwj/urldb/db/dto"
"github.com/ctwj/urldb/db/entity"
"github.com/gin-gonic/gin"
)
// GetCks 获取Cookie列表
func GetCks(c *gin.Context) {
cks, err := repoManager.CksRepository.FindAll()
if err != nil {
ErrorResponse(c, err.Error(), http.StatusInternalServerError)
return
}
// 使用新的逻辑创建 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)
}
SuccessResponse(c, responses)
}
// CreateCks 创建Cookie
func CreateCks(c *gin.Context) {
var req dto.CreateCksRequest
if err := c.ShouldBindJSON(&req); err != nil {
ErrorResponse(c, err.Error(), http.StatusBadRequest)
return
}
// 获取平台信息以确定服务类型
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
case "xunlei":
serviceType = panutils.Xunlei
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
}
var cks *entity.Cks
// 迅雷网盘,添加的时候 只获取token就好 然后刷新的时候, 再补充用户信息等
if serviceType == panutils.Xunlei {
xunleiService := service.(*panutils.XunleiPanService)
tokenData, err := xunleiService.GetAccessTokenByRefreshToken(req.Ck)
if err != nil {
ErrorResponse(c, "无法获取有效token: "+err.Error(), http.StatusBadRequest)
return
}
extra := panutils.XunleiExtraData{
Token: &tokenData,
Captcha: &panutils.CaptchaData{},
}
extraStr, _ := json.Marshal(extra)
// 创建Cks实体
cks = &entity.Cks{
PanID: req.PanID,
Idx: req.Idx,
Ck: tokenData.RefreshToken,
IsValid: true, // 根据VIP状态设置有效性
Space: 0,
LeftSpace: 0,
UsedSpace: 0,
Username: "-",
VipStatus: false,
ServiceType: "xunlei",
Extra: string(extraStr),
Remark: req.Remark,
}
} else {
// 获取用户信息
userInfo, err := service.GetUserInfo(&req.Ck)
if err != nil {
ErrorResponse(c, "无法获取用户信息,账号创建失败: "+err.Error(), http.StatusBadRequest)
return
}
leftSpaceBytes := userInfo.TotalSpace - userInfo.UsedSpace
// 创建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,
}
}
err = repoManager.CksRepository.Create(cks)
if err != nil {
ErrorResponse(c, err.Error(), http.StatusInternalServerError)
return
}
SuccessResponse(c, gin.H{
"message": "账号创建成功",
"cks": converter.ToCksResponse(cks),
})
}
// 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
}
// 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)
}
// UpdateCks 更新Cookie
func UpdateCks(c *gin.Context) {
idStr := c.Param("id")
id, err := strconv.ParseUint(idStr, 10, 32)
if err != nil {
ErrorResponse(c, "无效的ID", http.StatusBadRequest)
return
}
var req dto.UpdateCksRequest
if err := c.ShouldBindJSON(&req); err != nil {
ErrorResponse(c, err.Error(), http.StatusBadRequest)
return
}
cks, err := repoManager.CksRepository.FindByID(uint(id))
if err != nil {
ErrorResponse(c, "Cookie不存在", http.StatusNotFound)
return
}
if req.PanID != 0 {
cks.PanID = req.PanID
}
if req.Idx != 0 {
cks.Idx = req.Idx
}
if req.Ck != "" {
cks.Ck = req.Ck
}
// 对于 bool 类型,我们需要检查请求中是否包含该字段
// 由于 Go 的 JSON 解析,如果字段存在且为 false也会被正确解析
cks.IsValid = req.IsValid
if req.LeftSpace != 0 {
cks.LeftSpace = req.LeftSpace
}
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
}
if req.Remark != "" {
cks.Remark = req.Remark
}
// 使用专门的方法更新,确保更新所有字段包括零值
err = repoManager.CksRepository.UpdateWithAllFields(cks)
if err != nil {
ErrorResponse(c, err.Error(), http.StatusInternalServerError)
return
}
SuccessResponse(c, gin.H{"message": "Cookie更新成功"})
}
// DeleteCks 删除Cookie
func DeleteCks(c *gin.Context) {
idStr := c.Param("id")
id, err := strconv.ParseUint(idStr, 10, 32)
if err != nil {
ErrorResponse(c, "无效的ID", http.StatusBadRequest)
return
}
err = repoManager.CksRepository.Delete(uint(id))
if err != nil {
ErrorResponse(c, err.Error(), http.StatusInternalServerError)
return
}
SuccessResponse(c, gin.H{"message": "Cookie删除成功"})
}
// GetCksByID 根据ID获取Cookie详情使用全局repoManager
func GetCksByIDGlobal(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)
}
// 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
case "xunlei":
serviceType = panutils.Xunlei
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
}
var userInfo *panutils.UserInfo
service.SetCKSRepository(repoManager.CksRepository, *cks) // 迅雷需要初始化 token 后才能获取,
userInfo, err = service.GetUserInfo(&cks.Ck)
// switch s := service.(type) {
// case *panutils.XunleiPanService:
// userInfo, err = s.GetUserInfo(nil)
// default:
// userInfo, err = service.GetUserInfo(&cks.Ck)
// }
if err != nil {
ErrorResponse(c, "无法获取用户信息,刷新失败: "+err.Error(), http.StatusBadRequest)
return
}
leftSpaceBytes := userInfo.TotalSpace - userInfo.UsedSpace
// 更新账号信息
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状态更新有效性
err = repoManager.CksRepository.UpdateWithAllFields(cks)
if err != nil {
ErrorResponse(c, err.Error(), http.StatusInternalServerError)
return
}
SuccessResponse(c, gin.H{
"message": "容量信息刷新成功",
"cks": converter.ToCksResponse(cks),
})
}
// 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,
})
}