mirror of
https://github.com/ctwj/urldb.git
synced 2025-11-25 03:15:04 +08:00
update: 完善自动处理逻辑
This commit is contained in:
@@ -76,10 +76,4 @@
|
||||
1. 在提交代码时使用规范的提交信息2. 在Pull Request中描述您的更改
|
||||
3. 遵循项目的贡献指南
|
||||
|
||||
---
|
||||
|
||||
## 链接
|
||||
|
||||
- [项目主页](https://github.com/your-username/l9pan)
|
||||
- [问题反馈](https://github.com/your-username/l9pan/issues)
|
||||
- [讨论区](https://github.com/your-username/l9
|
||||
---
|
||||
@@ -17,19 +17,16 @@ var DB *gorm.DB
|
||||
// InitDB 初始化数据库连接
|
||||
func InitDB() error {
|
||||
host := os.Getenv("DB_HOST")
|
||||
fmt.Printf("DB_HOST=%s\n", host)
|
||||
if host == "" {
|
||||
host = "localhost"
|
||||
}
|
||||
|
||||
port := os.Getenv("DB_PORT")
|
||||
fmt.Printf("DB_HOST=%s\n", port)
|
||||
if port == "" {
|
||||
port = "5432"
|
||||
}
|
||||
|
||||
user := os.Getenv("DB_USER")
|
||||
fmt.Printf("DB_HOST=%s\n", user)
|
||||
if user == "" {
|
||||
user = "postgres"
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ type ResourceRepository interface {
|
||||
FindExists(url string, excludeID ...uint) (bool, error)
|
||||
BatchFindByURLs(urls []string) ([]entity.Resource, error)
|
||||
GetResourcesForTransfer(panID uint, sinceTime time.Time) ([]*entity.Resource, error)
|
||||
CreateResourceTag(resourceID, tagID uint) error
|
||||
}
|
||||
|
||||
// ResourceRepositoryImpl Resource的Repository实现
|
||||
@@ -333,7 +334,7 @@ func (r *ResourceRepositoryImpl) InvalidateCache() error {
|
||||
// FindExists 检查是否存在相同URL的资源
|
||||
func (r *ResourceRepositoryImpl) FindExists(url string, excludeID ...uint) (bool, error) {
|
||||
var count int64
|
||||
query := r.db.Model(&entity.Resource{}).Where("url = ?", url)
|
||||
query := r.db.Model(&entity.Resource{}).Where("url = ? or save_url ", url, url)
|
||||
|
||||
// 如果有排除ID,则排除该记录(用于更新时排除自己)
|
||||
if len(excludeID) > 0 {
|
||||
@@ -369,3 +370,12 @@ func (r *ResourceRepositoryImpl) GetResourcesForTransfer(panID uint, sinceTime t
|
||||
}
|
||||
return resources, nil
|
||||
}
|
||||
|
||||
// CreateResourceTag 创建资源与标签的关联
|
||||
func (r *ResourceRepositoryImpl) CreateResourceTag(resourceID, tagID uint) error {
|
||||
resourceTag := &entity.ResourceTag{
|
||||
ResourceID: resourceID,
|
||||
TagID: tagID,
|
||||
}
|
||||
return r.GetDB().Create(resourceTag).Error
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ type TagRepository interface {
|
||||
FindWithPagination(page, pageSize int) ([]entity.Tag, int64, error)
|
||||
Search(query string, page, pageSize int) ([]entity.Tag, int64, error)
|
||||
UpdateWithNulls(tag *entity.Tag) error
|
||||
GetByID(id uint) (*entity.Tag, error)
|
||||
}
|
||||
|
||||
// TagRepositoryImpl Tag的Repository实现
|
||||
@@ -144,3 +145,13 @@ func (r *TagRepositoryImpl) UpdateWithNulls(tag *entity.Tag) error {
|
||||
// 使用Select方法明确指定要更新的字段,包括null值
|
||||
return r.db.Model(tag).Select("name", "description", "category_id", "updated_at").Updates(tag).Error
|
||||
}
|
||||
|
||||
// GetByID 通过ID查找标签
|
||||
func (r *TagRepositoryImpl) GetByID(id uint) (*entity.Tag, error) {
|
||||
var tag entity.Tag
|
||||
err := r.db.First(&tag, id).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &tag, nil
|
||||
}
|
||||
|
||||
@@ -16,6 +16,8 @@ func GetSchedulerStatus(c *gin.Context) {
|
||||
repoManager.SystemConfigRepository,
|
||||
repoManager.PanRepository,
|
||||
repoManager.CksRepository,
|
||||
repoManager.TagRepository,
|
||||
repoManager.CategoryRepository,
|
||||
)
|
||||
|
||||
status := gin.H{
|
||||
@@ -36,6 +38,8 @@ func StartHotDramaScheduler(c *gin.Context) {
|
||||
repoManager.SystemConfigRepository,
|
||||
repoManager.PanRepository,
|
||||
repoManager.CksRepository,
|
||||
repoManager.TagRepository,
|
||||
repoManager.CategoryRepository,
|
||||
)
|
||||
if scheduler.IsHotDramaSchedulerRunning() {
|
||||
ErrorResponse(c, "热播剧定时任务已在运行中", http.StatusBadRequest)
|
||||
@@ -54,6 +58,8 @@ func StopHotDramaScheduler(c *gin.Context) {
|
||||
repoManager.SystemConfigRepository,
|
||||
repoManager.PanRepository,
|
||||
repoManager.CksRepository,
|
||||
repoManager.TagRepository,
|
||||
repoManager.CategoryRepository,
|
||||
)
|
||||
if !scheduler.IsHotDramaSchedulerRunning() {
|
||||
ErrorResponse(c, "热播剧定时任务未在运行", http.StatusBadRequest)
|
||||
@@ -72,6 +78,8 @@ func TriggerHotDramaScheduler(c *gin.Context) {
|
||||
repoManager.SystemConfigRepository,
|
||||
repoManager.PanRepository,
|
||||
repoManager.CksRepository,
|
||||
repoManager.TagRepository,
|
||||
repoManager.CategoryRepository,
|
||||
)
|
||||
scheduler.StartHotDramaScheduler() // 直接启动一次
|
||||
SuccessResponse(c, gin.H{"message": "手动触发热播剧定时任务成功"})
|
||||
@@ -86,6 +94,8 @@ func FetchHotDramaNames(c *gin.Context) {
|
||||
repoManager.SystemConfigRepository,
|
||||
repoManager.PanRepository,
|
||||
repoManager.CksRepository,
|
||||
repoManager.TagRepository,
|
||||
repoManager.CategoryRepository,
|
||||
)
|
||||
names, err := scheduler.GetHotDramaNames()
|
||||
if err != nil {
|
||||
@@ -104,6 +114,8 @@ func StartReadyResourceScheduler(c *gin.Context) {
|
||||
repoManager.SystemConfigRepository,
|
||||
repoManager.PanRepository,
|
||||
repoManager.CksRepository,
|
||||
repoManager.TagRepository,
|
||||
repoManager.CategoryRepository,
|
||||
)
|
||||
if scheduler.IsReadyResourceRunning() {
|
||||
ErrorResponse(c, "待处理资源自动处理任务已在运行中", http.StatusBadRequest)
|
||||
@@ -122,6 +134,8 @@ func StopReadyResourceScheduler(c *gin.Context) {
|
||||
repoManager.SystemConfigRepository,
|
||||
repoManager.PanRepository,
|
||||
repoManager.CksRepository,
|
||||
repoManager.TagRepository,
|
||||
repoManager.CategoryRepository,
|
||||
)
|
||||
if !scheduler.IsReadyResourceRunning() {
|
||||
ErrorResponse(c, "待处理资源自动处理任务未在运行", http.StatusBadRequest)
|
||||
@@ -140,6 +154,8 @@ func TriggerReadyResourceScheduler(c *gin.Context) {
|
||||
repoManager.SystemConfigRepository,
|
||||
repoManager.PanRepository,
|
||||
repoManager.CksRepository,
|
||||
repoManager.TagRepository,
|
||||
repoManager.CategoryRepository,
|
||||
)
|
||||
// 手动触发一次处理
|
||||
scheduler.ProcessReadyResources()
|
||||
@@ -155,6 +171,8 @@ func StartAutoTransferScheduler(c *gin.Context) {
|
||||
repoManager.SystemConfigRepository,
|
||||
repoManager.PanRepository,
|
||||
repoManager.CksRepository,
|
||||
repoManager.TagRepository,
|
||||
repoManager.CategoryRepository,
|
||||
)
|
||||
if scheduler.IsAutoTransferRunning() {
|
||||
ErrorResponse(c, "自动转存定时任务已在运行中", http.StatusBadRequest)
|
||||
@@ -173,6 +191,8 @@ func StopAutoTransferScheduler(c *gin.Context) {
|
||||
repoManager.SystemConfigRepository,
|
||||
repoManager.PanRepository,
|
||||
repoManager.CksRepository,
|
||||
repoManager.TagRepository,
|
||||
repoManager.CategoryRepository,
|
||||
)
|
||||
if !scheduler.IsAutoTransferRunning() {
|
||||
ErrorResponse(c, "自动转存定时任务未在运行", http.StatusBadRequest)
|
||||
@@ -191,6 +211,8 @@ func TriggerAutoTransferScheduler(c *gin.Context) {
|
||||
repoManager.SystemConfigRepository,
|
||||
repoManager.PanRepository,
|
||||
repoManager.CksRepository,
|
||||
repoManager.TagRepository,
|
||||
repoManager.CategoryRepository,
|
||||
)
|
||||
// 手动触发一次处理
|
||||
scheduler.ProcessAutoTransfer()
|
||||
|
||||
@@ -164,6 +164,8 @@ func UpdateSystemConfig(c *gin.Context) {
|
||||
repoManager.SystemConfigRepository,
|
||||
repoManager.PanRepository,
|
||||
repoManager.CksRepository,
|
||||
repoManager.TagRepository,
|
||||
repoManager.CategoryRepository,
|
||||
)
|
||||
if scheduler != nil {
|
||||
scheduler.UpdateSchedulerStatusWithAutoTransfer(req.AutoFetchHotDramaEnabled, req.AutoProcessReadyResources, req.AutoTransferEnabled)
|
||||
|
||||
2
main.go
2
main.go
@@ -44,6 +44,8 @@ func main() {
|
||||
repoManager.SystemConfigRepository,
|
||||
repoManager.PanRepository,
|
||||
repoManager.CksRepository,
|
||||
repoManager.TagRepository,
|
||||
repoManager.CategoryRepository,
|
||||
)
|
||||
|
||||
// 检查系统配置,决定是否启动各种自动任务
|
||||
|
||||
@@ -18,10 +18,10 @@ var (
|
||||
)
|
||||
|
||||
// GetGlobalScheduler 获取全局调度器实例(单例模式)
|
||||
func GetGlobalScheduler(hotDramaRepo repo.HotDramaRepository, readyResourceRepo repo.ReadyResourceRepository, resourceRepo repo.ResourceRepository, systemConfigRepo repo.SystemConfigRepository, panRepo repo.PanRepository, cksRepo repo.CksRepository) *GlobalScheduler {
|
||||
func GetGlobalScheduler(hotDramaRepo repo.HotDramaRepository, readyResourceRepo repo.ReadyResourceRepository, resourceRepo repo.ResourceRepository, systemConfigRepo repo.SystemConfigRepository, panRepo repo.PanRepository, cksRepo repo.CksRepository, tagRepo repo.TagRepository, categoryRepo repo.CategoryRepository) *GlobalScheduler {
|
||||
once.Do(func() {
|
||||
globalScheduler = &GlobalScheduler{
|
||||
scheduler: NewScheduler(hotDramaRepo, readyResourceRepo, resourceRepo, systemConfigRepo, panRepo, cksRepo),
|
||||
scheduler: NewScheduler(hotDramaRepo, readyResourceRepo, resourceRepo, systemConfigRepo, panRepo, cksRepo, tagRepo, categoryRepo),
|
||||
}
|
||||
})
|
||||
return globalScheduler
|
||||
|
||||
@@ -16,13 +16,16 @@ import (
|
||||
|
||||
// Scheduler 定时任务管理器
|
||||
type Scheduler struct {
|
||||
doubanService *DoubanService
|
||||
hotDramaRepo repo.HotDramaRepository
|
||||
readyResourceRepo repo.ReadyResourceRepository
|
||||
resourceRepo repo.ResourceRepository
|
||||
systemConfigRepo repo.SystemConfigRepository
|
||||
panRepo repo.PanRepository
|
||||
cksRepo repo.CksRepository
|
||||
doubanService *DoubanService
|
||||
hotDramaRepo repo.HotDramaRepository
|
||||
readyResourceRepo repo.ReadyResourceRepository
|
||||
resourceRepo repo.ResourceRepository
|
||||
systemConfigRepo repo.SystemConfigRepository
|
||||
panRepo repo.PanRepository
|
||||
cksRepo repo.CksRepository
|
||||
// 新增
|
||||
tagRepo repo.TagRepository
|
||||
categoryRepo repo.CategoryRepository
|
||||
stopChan chan bool
|
||||
isRunning bool
|
||||
readyResourceRunning bool
|
||||
@@ -37,7 +40,7 @@ type Scheduler struct {
|
||||
}
|
||||
|
||||
// NewScheduler 创建新的定时任务管理器
|
||||
func NewScheduler(hotDramaRepo repo.HotDramaRepository, readyResourceRepo repo.ReadyResourceRepository, resourceRepo repo.ResourceRepository, systemConfigRepo repo.SystemConfigRepository, panRepo repo.PanRepository, cksRepo repo.CksRepository) *Scheduler {
|
||||
func NewScheduler(hotDramaRepo repo.HotDramaRepository, readyResourceRepo repo.ReadyResourceRepository, resourceRepo repo.ResourceRepository, systemConfigRepo repo.SystemConfigRepository, panRepo repo.PanRepository, cksRepo repo.CksRepository, tagRepo repo.TagRepository, categoryRepo repo.CategoryRepository) *Scheduler {
|
||||
return &Scheduler{
|
||||
doubanService: NewDoubanService(),
|
||||
hotDramaRepo: hotDramaRepo,
|
||||
@@ -46,6 +49,8 @@ func NewScheduler(hotDramaRepo repo.HotDramaRepository, readyResourceRepo repo.R
|
||||
systemConfigRepo: systemConfigRepo,
|
||||
panRepo: panRepo,
|
||||
cksRepo: cksRepo,
|
||||
tagRepo: tagRepo,
|
||||
categoryRepo: categoryRepo,
|
||||
stopChan: make(chan bool),
|
||||
isRunning: false,
|
||||
readyResourceRunning: false,
|
||||
@@ -401,6 +406,17 @@ func (s *Scheduler) convertReadyResourceToResource(readyResource entity.ReadyRes
|
||||
|
||||
Debug("检测到服务类型: %s, 分享ID: %s", serviceType.String(), shareID)
|
||||
|
||||
resource := &entity.Resource{
|
||||
Title: derefString(readyResource.Title),
|
||||
Description: readyResource.Description,
|
||||
URL: readyResource.URL,
|
||||
Cover: readyResource.Img,
|
||||
IsValid: true,
|
||||
IsPublic: true,
|
||||
Key: readyResource.Key,
|
||||
PanID: s.getPanIDByServiceType(serviceType),
|
||||
}
|
||||
|
||||
// 不是夸克,直接保存,
|
||||
if serviceType != panutils.Quark {
|
||||
// 检测是否有效
|
||||
@@ -410,67 +426,67 @@ func (s *Scheduler) convertReadyResourceToResource(readyResource entity.ReadyRes
|
||||
return nil
|
||||
}
|
||||
|
||||
// 入库
|
||||
}
|
||||
|
||||
// 准备配置
|
||||
config := &panutils.PanConfig{
|
||||
URL: readyResource.URL,
|
||||
Code: "", // 可以从readyResource中获取
|
||||
IsType: 1, // 转存并分享后的资源信息 0 转存后分享, 1 只获取基本信息
|
||||
ExpiredType: 1, // 永久分享
|
||||
AdFid: "",
|
||||
Stoken: "",
|
||||
}
|
||||
|
||||
// 通过工厂获取对应的网盘服务单例
|
||||
panService, err := factory.CreatePanService(readyResource.URL, config)
|
||||
if err != nil {
|
||||
Error("获取网盘服务失败: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
// 统一处理:尝试转存获取标题
|
||||
result, err := panService.Transfer(shareID)
|
||||
if err != nil {
|
||||
Error("网盘信息获取失败: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
if !result.Success {
|
||||
Error("网盘信息获取失败: %s", result.Message)
|
||||
return nil
|
||||
}
|
||||
|
||||
// 提取转存结果
|
||||
if resultData, ok := result.Data.(map[string]interface{}); ok {
|
||||
title := resultData["title"].(string)
|
||||
shareURL := resultData["shareUrl"].(string)
|
||||
// fid := resultData["fid"].(string) // 暂时未使用
|
||||
|
||||
// 创建资源记录
|
||||
resource := &entity.Resource{
|
||||
Title: title,
|
||||
Description: readyResource.Description,
|
||||
URL: shareURL,
|
||||
PanID: s.getPanIDByServiceType(serviceType),
|
||||
IsValid: true,
|
||||
IsPublic: true,
|
||||
Key: readyResource.Key,
|
||||
} else {
|
||||
// 准备配置
|
||||
config := &panutils.PanConfig{
|
||||
URL: readyResource.URL,
|
||||
Code: "", // 可以从readyResource中获取
|
||||
IsType: 1, // 转存并分享后的资源信息 0 转存后分享, 1 只获取基本信息
|
||||
ExpiredType: 1, // 永久分享
|
||||
AdFid: "",
|
||||
Stoken: "",
|
||||
}
|
||||
|
||||
// 如果有分类信息,尝试查找或创建分类
|
||||
if readyResource.Category != "" {
|
||||
categoryID, err := s.getOrCreateCategory(readyResource.Category)
|
||||
if err == nil {
|
||||
resource.CategoryID = &categoryID
|
||||
}
|
||||
// 通过工厂获取对应的网盘服务单例
|
||||
panService, err := factory.CreatePanService(readyResource.URL, config)
|
||||
if err != nil {
|
||||
Error("获取网盘服务失败: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
// 统一处理:尝试转存获取标题
|
||||
result, err := panService.Transfer(shareID)
|
||||
if err != nil {
|
||||
Error("网盘信息获取失败: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
if !result.Success {
|
||||
Error("网盘信息获取失败: %s", result.Message)
|
||||
return nil
|
||||
}
|
||||
|
||||
return s.resourceRepo.Create(resource)
|
||||
}
|
||||
|
||||
Error("转存结果格式异常")
|
||||
// 处理标签
|
||||
tagIDs, err := s.handleTags(readyResource.Tags)
|
||||
if err != nil || tagIDs == nil {
|
||||
Error("处理标签失败: %v", err)
|
||||
return err
|
||||
}
|
||||
// 处理分类
|
||||
categoryID, err := s.resolveCategory(readyResource.Category, tagIDs)
|
||||
if err != nil {
|
||||
Error("处理分类失败: %v", err)
|
||||
return err
|
||||
}
|
||||
if categoryID != nil {
|
||||
resource.CategoryID = categoryID
|
||||
}
|
||||
// 保存资源
|
||||
err = s.resourceRepo.Create(resource)
|
||||
if err != nil {
|
||||
Error("资源保存失败: %v", err)
|
||||
return err
|
||||
}
|
||||
// 插入 resource_tags 关联
|
||||
for _, tagID := range tagIDs {
|
||||
err := s.resourceRepo.CreateResourceTag(resource.ID, tagID)
|
||||
if err != nil {
|
||||
Error("插入资源标签关联失败: %v", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -863,3 +879,61 @@ func (s *Scheduler) calculateAccountScore(account *entity.Cks) int64 {
|
||||
|
||||
return score
|
||||
}
|
||||
|
||||
// 分割标签,支持中英文逗号
|
||||
func splitTags(tagStr string) []string {
|
||||
tagStr = strings.ReplaceAll(tagStr, ",", ",")
|
||||
return strings.Split(tagStr, ",")
|
||||
}
|
||||
|
||||
// 处理标签,返回所有标签ID
|
||||
func (s *Scheduler) handleTags(tagStr string) ([]uint, error) {
|
||||
if tagStr == "" {
|
||||
return nil, nil
|
||||
}
|
||||
tagNames := splitTags(tagStr)
|
||||
var tagIDs []uint
|
||||
for _, name := range tagNames {
|
||||
name = strings.TrimSpace(name)
|
||||
if name == "" {
|
||||
continue
|
||||
}
|
||||
tag, err := s.tagRepo.FindByName(name)
|
||||
if err != nil || tag == nil {
|
||||
// 不存在则新建
|
||||
tag = &entity.Tag{Name: name}
|
||||
err = s.tagRepo.Create(tag)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
tagIDs = append(tagIDs, tag.ID)
|
||||
}
|
||||
return tagIDs, nil
|
||||
}
|
||||
|
||||
// 分类处理逻辑
|
||||
func (s *Scheduler) resolveCategory(categoryName string, tagIDs []uint) (*uint, error) {
|
||||
if categoryName != "" {
|
||||
cat, err := s.categoryRepo.FindByName(categoryName)
|
||||
if err == nil && cat != nil {
|
||||
return &cat.ID, nil
|
||||
}
|
||||
}
|
||||
// 没有分类,尝试用标签反查
|
||||
for _, tagID := range tagIDs {
|
||||
tag, err := s.tagRepo.GetByID(tagID)
|
||||
if err == nil && tag != nil && tag.CategoryID != nil {
|
||||
return tag.CategoryID, nil
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// 工具函数,解引用string指针
|
||||
func derefString(s *string) string {
|
||||
if s == nil {
|
||||
return ""
|
||||
}
|
||||
return *s
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user