233 lines
5.0 KiB
Go
233 lines
5.0 KiB
Go
// 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)
|
|
}
|
|
}
|
|
|