refactor: modularize downloader architecture

This commit is contained in:
OpenClaw Agent
2026-09-16 06:41:45 +08:00
parent 6c585ff835
commit 285064d144
11 changed files with 766 additions and 558 deletions
+110
View File
@@ -0,0 +1,110 @@
package main
import (
"io"
"strconv"
"strings"
"github.com/gin-gonic/gin"
)
func (a *App) search(c *gin.Context) {
keyword := strings.TrimSpace(c.Query("keyword"))
if keyword == "" {
c.JSON(400, gin.H{"error": "keyword required"})
return
}
source := c.DefaultQuery("source", "kw")
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
if page < 1 {
page = 1
}
limit, _ := strconv.Atoi(c.DefaultQuery("limit", "20"))
if limit < 1 {
limit = 20
}
resp, err := a.am.Search(keyword, source, page, limit)
if err != nil {
c.JSON(502, gin.H{"error": err.Error()})
return
}
defer resp.Body.Close()
c.Status(resp.StatusCode)
_, _ = io.Copy(c.Writer, resp.Body)
}
func (a *App) listTasks(c *gin.Context) {
var ts []Task
if err := a.db.Order("id desc").Limit(100).Find(&ts).Error; err != nil {
c.JSON(500, gin.H{"error": err.Error()})
return
}
c.JSON(200, gin.H{"data": ts})
}
func (a *App) addTask(c *gin.Context) {
var in SongRequest
if c.BindJSON(&in) != nil || in.RID == "" || in.Title == "" {
c.JSON(400, gin.H{"error": "source/rid/title required"})
return
}
if in.Source == "" {
in.Source = "kw"
}
if in.Quality == "" {
in.Quality = a.cfg.DefaultQuality
}
var existing Task
err := a.db.Where("source = ? AND r_id = ? AND quality = ?", in.Source, in.RID, in.Quality).Order("id desc").First(&existing).Error
if err == nil {
if existing.Status != "error" {
c.JSON(200, existing)
return
}
a.db.Model(&existing).Updates(map[string]any{"title": in.Title, "artist": in.Artist, "album": in.Album, "pic": in.Pic, "status": "pending", "error": ""})
a.queue <- existing.ID
c.JSON(202, existing)
return
}
t := Task{Source: in.Source, RID: in.RID, Title: in.Title, Artist: in.Artist, Album: in.Album, Pic: in.Pic, Quality: in.Quality, Status: "pending"}
if err := a.db.Create(&t).Error; err != nil {
if a.db.Where("source = ? AND r_id = ? AND quality = ?", in.Source, in.RID, in.Quality).Order("id desc").First(&existing).Error == nil {
c.JSON(200, existing)
return
}
c.JSON(500, gin.H{"error": err.Error()})
return
}
a.queue <- t.ID
c.JSON(202, t)
}
func (a *App) retryTask(c *gin.Context) {
id, err := strconv.ParseUint(c.Param("id"), 10, 64)
if err != nil {
c.Status(400)
return
}
var t Task
if a.db.First(&t, id).Error != nil {
c.Status(404)
return
}
a.db.Model(&t).Updates(map[string]any{"status": "pending", "error": "", "progress": 0, "downloaded_bytes": 0})
t.Status, t.Error, t.Progress, t.DownloadedBytes = "pending", "", 0, 0
a.queue <- t.ID
c.JSON(202, t)
}
func (a *App) deleteTask(c *gin.Context) {
id, err := strconv.ParseUint(c.Param("id"), 10, 64)
if err != nil {
c.Status(400)
return
}
if err := a.db.Delete(&Task{}, id).Error; err != nil {
c.JSON(500, gin.H{"error": err.Error()})
return
}
c.Status(204)
}