package router import ( "encoding/json" "fmt" "net/http" "os/exec" "runtime" "strconv" "bilidown/internal/task" "bilidown/internal/util" ) func createTask(w http.ResponseWriter, r *http.Request) { defer r.Body.Close() if r.Method != http.MethodPost { util.Res{Success: false, Message: "不支持的请求方法"}.Write(w) return } var body []task.TaskInDB err := json.NewDecoder(r.Body).Decode(&body) if err != nil { util.Res{Success: false, Message: "参数错误"}.Write(w) return } db := util.MustGetDB() defer db.Close() // 预先获取下载目录,避免循环中重复查询 folder, err := util.GetCurrentFolder(db) if err != nil { util.Res{Success: false, Message: fmt.Sprintf("获取下载目录失败: %v", err)}.Write(w) return } for _, item := range body { if !util.CheckBvidFormat(item.Bvid) { util.Res{Success: false, Message: "bvid 格式错误"}.Write(w) return } if item.Cover == "" || item.Title == "" || item.Owner == "" { util.Res{Success: false, Message: "参数错误"}.Write(w) return } if !util.IsValidURL(item.Cover) { util.Res{Success: false, Message: "封面链接格式错误"}.Write(w) return } if !util.IsValidURL(item.Audio) { util.Res{Success: false, Message: "音频链接格式错误"}.Write(w) return } if !util.IsValidURL(item.Video) { util.Res{Success: false, Message: "视频链接格式错误"}.Write(w) return } if !util.IsValidFormatCode(item.Format) { util.Res{Success: false, Message: "清晰度代码错误"}.Write(w) return } item.Folder = folder item.Status = "waiting" _task := task.Task{TaskInDB: item} _task.Title = util.FilterFileName(_task.Title) err = _task.Create(db) if err != nil { util.Res{Success: false, Message: fmt.Sprintf("_task.Create: %v.", err)}.Write(w) return } go _task.Start() } util.Res{Success: true, Message: "创建成功"}.Write(w) } func getActiveTask(w http.ResponseWriter, r *http.Request) { util.Res{Success: true, Data: task.GlobalTaskList}.Write(w) } func getTaskList(w http.ResponseWriter, r *http.Request) { err := r.ParseForm() if err != nil { util.Res{Success: false, Message: "参数错误"}.Write(w) return } db := util.MustGetDB() defer db.Close() page, err := strconv.Atoi(r.FormValue("page")) if err != nil { page = 0 } pageSize, err := strconv.Atoi(r.FormValue("pageSize")) if err != nil { pageSize = 360 } tasks, err := task.GetTaskList(db, page, pageSize) if err != nil { util.Res{Success: false, Message: err.Error()}.Write(w) return } util.Res{Success: true, Message: "获取成功", Data: tasks}.Write(w) } // showFile 调用 Explorer 查看文件位置 func showFile(w http.ResponseWriter, r *http.Request) { if err := r.ParseForm(); err != nil { util.Res{Success: false, Message: "参数错误"}.Write(w) return } filePath := r.FormValue("filePath") var cmd *exec.Cmd // 根据操作系统选择命令 switch runtime.GOOS { case "windows": // Windows 使用 explorer cmd = exec.Command("explorer", "/select,", filePath) case "darwin": // macOS 使用 open cmd = exec.Command("open", "-R", filePath) case "linux": // Linux 使用 xdg-open cmd = exec.Command("xdg-open", filePath) default: util.Res{Success: false, Message: "不支持的操作系统"}.Write(w) return } err := cmd.Start() if err != nil { util.Res{Success: false, Message: err.Error()}.Write(w) return } util.Res{Success: true, Message: "操作成功"}.Write(w) } func deleteTask(w http.ResponseWriter, r *http.Request) { // 支持单个删除(GET 参数 id)和批量删除(POST 参数 ids) var taskIDs []int if r.Method == http.MethodPost { defer r.Body.Close() var body struct { IDs []int `json:"ids"` } if err := json.NewDecoder(r.Body).Decode(&body); err != nil { util.Res{Success: false, Message: "参数错误"}.Write(w) return } taskIDs = body.IDs } else { taskIDStr := r.FormValue("id") taskID, err := strconv.Atoi(taskIDStr) if err != nil { util.Res{Success: false, Message: "参数错误"}.Write(w) return } taskIDs = []int{taskID} } if len(taskIDs) == 0 { util.Res{Success: false, Message: "参数错误"}.Write(w) return } db := util.MustGetDB() defer db.Close() // 批量删除结果 successCount := 0 failedTasks := []struct { ID int Error string }{} for _, taskID := range taskIDs { // 只删除数据库记录,不删除已下载的视频文件 err := task.DeleteTask(db, taskID) if err != nil { failedTasks = append(failedTasks, struct { ID int Error string }{ID: taskID, Error: fmt.Sprintf("数据库删除失败: %v", err)}) continue } successCount++ } if len(failedTasks) == 0 { util.Res{Success: true, Message: fmt.Sprintf("成功删除 %d 个任务", successCount)}.Write(w) } else { util.Res{ Success: successCount > 0, Message: fmt.Sprintf("成功删除 %d 个任务,失败 %d 个", successCount, len(failedTasks)), Data: failedTasks, }.Write(w) } } func cancelTask(w http.ResponseWriter, r *http.Request) { // 支持单个取消(GET 参数 id)和批量取消(POST 参数 ids) var taskIDs []int64 if r.Method == http.MethodPost { defer r.Body.Close() var body struct { IDs []int64 `json:"ids"` } if err := json.NewDecoder(r.Body).Decode(&body); err != nil { util.Res{Success: false, Message: "参数错误"}.Write(w) return } taskIDs = body.IDs } else { taskIDStr := r.FormValue("id") taskID, err := strconv.ParseInt(taskIDStr, 10, 64) if err != nil { util.Res{Success: false, Message: "参数错误"}.Write(w) return } taskIDs = []int64{taskID} } if len(taskIDs) == 0 { util.Res{Success: false, Message: "参数错误"}.Write(w) return } // 批量取消结果 successCount := 0 failedIDs := []int64{} for _, taskID := range taskIDs { if task.CancelTask(taskID) { successCount++ } else { failedIDs = append(failedIDs, taskID) } } if len(failedIDs) == 0 { util.Res{Success: true, Message: fmt.Sprintf("成功取消 %d 个任务", successCount)}.Write(w) } else { util.Res{ Success: successCount > 0, Message: fmt.Sprintf("成功取消 %d 个任务,失败 %d 个", successCount, len(failedIDs)), Data: failedIDs, }.Write(w) } }