shelfy/internal/download/jobs.go

233 lines
5.0 KiB
Go
Raw Normal View History

2025-06-12 08:57:10 +00:00
// internal/download/jobs.go
package download
import (
"app/shelfly/internal/debridlink"
"context"
"encoding/json"
"net/http"
"strconv"
"sync"
"time"
"github.com/gorilla/mux"
"gorm.io/gorm"
)
type DownloadJob struct {
ID uint `gorm:"primaryKey"`
RemoteID string `gorm:"index"`
FileName string `gorm:"size:255"`
Status string `gorm:"size:50"`
Speed string `gorm:"size:50"`
StreamURL string `gorm:"-" json:"stream_url"`
ErrorMsg string `gorm:"-" json:"error_msg"`
CreatedAt time.Time `gorm:"autoCreateTime"`
UpdatedAt time.Time `gorm:"autoUpdateTime"`
Link string `gorm:"size:512"`
}
var (
jobs = make(map[string]*DownloadJob)
jobsMu sync.Mutex
)
func AddJob(link string, pathID uint, db *gorm.DB) *DownloadJob {
id := time.Now().UnixNano()
job := &DownloadJob{
ID: uint(id),
Link: link, // ← important !
RemoteID: "",
FileName: extractFileName(link),
Status: "added",
Speed: "",
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
}
jobsMu.Lock()
jobs[strconv.FormatUint(uint64(id), 10)] = job
jobsMu.Unlock()
db.Create(job)
return job
}
func startDownload(job *DownloadJob, link string, client *debridlink.Client, db *gorm.DB) {
ctx := context.Background()
job.Status = "downloading"
linkResp, err := client.AddLink(ctx, link)
if err != nil {
job.Status = "error"
job.ErrorMsg = err.Error()
db.Save(job)
return
}
job.RemoteID = linkResp.ID
db.Save(job)
go syncDownloadStatus(job, client, db)
}
func syncDownloadStatus(job *DownloadJob, client *debridlink.Client, db *gorm.DB) {
ctx := context.Background()
var checkCount int
for {
if job.Status != "downloading" {
return
}
links, err := client.ListLinks(ctx)
if err != nil {
job.Status = "error"
job.ErrorMsg = err.Error()
db.Save(job)
return
}
for _, l := range links {
if l.ID == job.RemoteID {
job.Status = l.Status
checkCount++
if checkCount%2 == 0 {
job.Speed = "~2 MB/s"
} else {
job.Speed = "~1.4 MB/s"
}
if l.Status == "downloaded" {
files, err := client.ListFiles(ctx, l.ID)
if err == nil && len(files) > 0 {
transcodeID, err := client.CreateTranscode(ctx, files[0].ID, "original")
if err == nil {
job.StreamURL = "https://debrid-link.com/stream/" + transcodeID
}
}
}
db.Save(job)
if l.Status == "downloaded" || l.Status == "error" {
_ = client.RemoveLinks(ctx, []string{l.ID})
return
}
}
}
time.Sleep(2 * time.Second)
}
}
func ListJobs() []*DownloadJob {
jobsMu.Lock()
defer jobsMu.Unlock()
var list []*DownloadJob
for _, job := range jobs {
list = append(list, job)
}
return list
}
func PauseJob(id string) {
jobsMu.Lock()
defer jobsMu.Unlock()
if job, ok := jobs[id]; ok && job.Status == "downloading" {
job.Status = "paused"
}
}
func ResumeJob(id string, client *debridlink.Client, db *gorm.DB) {
jobsMu.Lock()
defer jobsMu.Unlock()
if job, ok := jobs[id]; ok && job.Status == "paused" {
job.Status = "downloading"
db.Save(job)
go syncDownloadStatus(job, client, db)
}
}
func DeleteJob(id string) {
jobsMu.Lock()
defer jobsMu.Unlock()
delete(jobs, id)
}
func generateID() string {
return time.Now().Format("20060102150405.000")
}
func extractFileName(link string) string {
return "file_from_" + link
}
func HandleListJobs(w http.ResponseWriter, r *http.Request) {
jobs := ListJobs()
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(jobs)
}
func HandlePauseJob(w http.ResponseWriter, r *http.Request) {
id := mux.Vars(r)["id"]
PauseJob(id)
w.WriteHeader(http.StatusNoContent)
}
func HandleResumeJob(db *gorm.DB) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
id := mux.Vars(r)["id"]
client := debridlink.NewClient(db)
account := getFirstActiveAccount(client)
if account == nil {
http.Error(w, "Aucun compte actif", http.StatusBadRequest)
return
}
client.SetAccount(account)
ResumeJob(id, client, db)
w.WriteHeader(http.StatusNoContent)
}
}
func HandleDeleteJob(w http.ResponseWriter, r *http.Request) {
id := mux.Vars(r)["id"]
DeleteJob(id)
w.WriteHeader(http.StatusNoContent)
}
func getFirstActiveAccount(client *debridlink.Client) *debridlink.DebridAccount {
ctx := context.Background()
accounts, err := client.ListDebridAccounts(ctx)
if err != nil {
return nil
}
for _, acc := range accounts {
if acc.IsActive {
return &acc
}
}
return nil
}
func HandleStartJob(db *gorm.DB) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
id := mux.Vars(r)["id"]
jobsMu.Lock()
job, exists := jobs[id]
jobsMu.Unlock()
if !exists {
http.Error(w, "Job not found", http.StatusNotFound)
return
}
client := debridlink.NewClient(db)
account := getFirstActiveAccount(client)
if account == nil {
http.Error(w, "Aucun compte actif", http.StatusBadRequest)
return
}
client.SetAccount(account)
go startDownload(job, job.Link, client, db)
w.WriteHeader(http.StatusNoContent)
}
}