fix mutli dowload

This commit is contained in:
cangui 2025-09-28 15:44:15 +02:00
parent d0eebe3ffc
commit b52729630a

View File

@ -25,7 +25,27 @@ var seriesRegex = regexp.MustCompile(`^(.+?)\.S\d{2}E\d{2}`)
var ( var (
jobs = make(map[string]*runner.DownloadJob) jobs = make(map[string]*runner.DownloadJob)
jobsMu sync.Mutex jobsMu sync.Mutex
// --- Ajouts ---
inFlightMu sync.Mutex
inFlight = map[string]struct{}{} // set des jobs déjà en cours (par id)
parallelism = 4 // <— ajuste le nombre de DL en parallèle
sem = make(chan struct{}, parallelism)
) )
func tryMarkInFlight(id string) bool {
inFlightMu.Lock()
defer inFlightMu.Unlock()
if _, ok := inFlight[id]; ok {
return false
}
inFlight[id] = struct{}{}
return true
}
func unmarkInFlight(id string) {
inFlightMu.Lock()
delete(inFlight, id)
inFlightMu.Unlock()
}
func HandleAddJobsMultiple(db *gorm.DB) gin.HandlerFunc { func HandleAddJobsMultiple(db *gorm.DB) gin.HandlerFunc {
return func(c *gin.Context) { return func(c *gin.Context) {
// 1. Parsing des champs du formulaire // 1. Parsing des champs du formulaire
@ -171,15 +191,21 @@ func HandleStartJob(db *gorm.DB) gin.HandlerFunc {
id := c.Param("id") id := c.Param("id")
log.Printf("[StartJob] ID = %s", id) log.Printf("[StartJob] ID = %s", id)
// 1. Vérifie si le job est déjà en mémoire // Empêche un job déjà en cours d'être relancé
if !tryMarkInFlight(id) {
log.Printf("[StartJob] Job %s déjà en cours, on ignore", id)
c.Status(http.StatusNoContent)
return
}
// Récupération du job depuis la mémoire ou la DB
jobsMu.Lock() jobsMu.Lock()
job, exists := jobs[id] job, exists := jobs[id]
jobsMu.Unlock() jobsMu.Unlock()
// 2. Sinon, récupère depuis la BDD
if !exists { if !exists {
var j runner.DownloadJob var j runner.DownloadJob
if err := db.First(&j, "id = ?", id).Error; err != nil { if err := db.First(&j, "id = ?", id).Error; err != nil {
unmarkInFlight(id)
c.JSON(http.StatusNotFound, gin.H{"error": "Job introuvable"}) c.JSON(http.StatusNotFound, gin.H{"error": "Job introuvable"})
return return
} }
@ -190,20 +216,33 @@ func HandleStartJob(db *gorm.DB) gin.HandlerFunc {
jobsMu.Unlock() jobsMu.Unlock()
} }
clt:= client.NewClient(db) // Init client Debrid-Link
clt := client.NewClient(db)
account := runner.GetFirstActiveAccount(clt) account := runner.GetFirstActiveAccount(clt)
if account == nil { if account == nil {
unmarkInFlight(id)
c.JSON(http.StatusBadRequest, gin.H{"error": "Aucun compte Debrid-Link actif"}) c.JSON(http.StatusBadRequest, gin.H{"error": "Aucun compte Debrid-Link actif"})
return return
} }
clt.SetAccount(account) clt.SetAccount(account)
go runner.StartDownload(job, job.Link, clt, db) // Lancement asynchrone avec limite de parallélisme
go func(job *runner.DownloadJob) {
sem <- struct{}{} // bloque si trop de jobs en cours
defer func() {
<-sem
unmarkInFlight(job.ID)
runner.Broadcast() runner.Broadcast()
}()
runner.StartDownload(job, job.Link, clt, db)
}(job)
runner.Broadcast()
c.Status(http.StatusNoContent) c.Status(http.StatusNoContent)
} }
} }
func HandlePauseJob() gin.HandlerFunc { func HandlePauseJob() gin.HandlerFunc {
return func(c *gin.Context) { return func(c *gin.Context) {
id := c.Param("id") id := c.Param("id")
@ -216,14 +255,23 @@ func HandlePauseJob() gin.HandlerFunc {
func HandleResumeJob(db *gorm.DB) gin.HandlerFunc { func HandleResumeJob(db *gorm.DB) gin.HandlerFunc {
return func(c *gin.Context) { return func(c *gin.Context) {
id := c.Param("id") id := c.Param("id")
log.Printf("[ResumeJob] ID = %s", id)
// Empêche un job déjà en cours d'être relancé
if !tryMarkInFlight(id) {
log.Printf("[ResumeJob] Job %s déjà en cours, on ignore", id)
c.Status(http.StatusNoContent)
return
}
// Récupération du job depuis la mémoire ou la DB
jobsMu.Lock() jobsMu.Lock()
job, exists := jobs[id] job, exists := jobs[id]
jobsMu.Unlock() jobsMu.Unlock()
if !exists { if !exists {
var j runner.DownloadJob var j runner.DownloadJob
if err := db.First(&j, "id = ?", id).Error; err != nil { if err := db.First(&j, "id = ?", id).Error; err != nil {
unmarkInFlight(id)
c.JSON(http.StatusNotFound, gin.H{"error": "Job introuvable"}) c.JSON(http.StatusNotFound, gin.H{"error": "Job introuvable"})
return return
} }
@ -234,17 +282,29 @@ func HandleResumeJob(db *gorm.DB) gin.HandlerFunc {
jobsMu.Unlock() jobsMu.Unlock()
} }
// Init client Debrid-Link
clt := client.NewClient(db) clt := client.NewClient(db)
account := runner.GetFirstActiveAccount(clt) account := runner.GetFirstActiveAccount(clt)
if account == nil { if account == nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Aucun compte actif"}) unmarkInFlight(id)
c.JSON(http.StatusBadRequest, gin.H{"error": "Aucun compte Debrid-Link actif"})
return return
} }
clt.SetAccount(account) clt.SetAccount(account)
go runner.StartDownload(job, job.Link, clt, db) // Reprise asynchrone avec limite de parallélisme
go func(job *runner.DownloadJob) {
sem <- struct{}{} // bloque si trop de jobs en cours
defer func() {
<-sem
unmarkInFlight(job.ID)
runner.Broadcast() runner.Broadcast()
}()
runner.StartDownload(job, job.Link, clt, db)
}(job)
runner.Broadcast()
c.Status(http.StatusNoContent) c.Status(http.StatusNoContent)
} }
} }