up
This commit is contained in:
parent
91d1d97361
commit
e1955871b2
@ -184,12 +184,22 @@ func ListJobs(db *gorm.DB) []*DownloadJob {
|
||||
func StartDownload(job *DownloadJob, downloadURL string, client *client.Client, db *gorm.DB) {
|
||||
UpdateJobStatus(job.ID, "downloading", db)
|
||||
|
||||
var path models.PathDownload
|
||||
if err := db.First(&path, job.PathID).Error; err != nil {
|
||||
// Récupère l'entrée (Path="Film" / "Série" / ...)
|
||||
var p models.PathDownload
|
||||
if err := db.First(&p, job.PathID).Error; err != nil {
|
||||
UpdateJobStatus(job.ID, "failed", db)
|
||||
return
|
||||
}
|
||||
|
||||
// ★ Chemin physique = upload/<Path>
|
||||
diskBase := filepath.Join("upload", p.Path)
|
||||
if err := os.MkdirAll(diskBase, 0o755); err != nil {
|
||||
log.Printf("[ERROR] Création dossier '%s' : %v", diskBase, err)
|
||||
UpdateJobStatus(job.ID, "failed", db)
|
||||
return
|
||||
}
|
||||
|
||||
// HEAD pour taille + Accept-Ranges
|
||||
resp, err := http.Head(downloadURL)
|
||||
if err != nil || resp.StatusCode != http.StatusOK {
|
||||
UpdateJobStatus(job.ID, "failed", db)
|
||||
@ -201,10 +211,11 @@ func StartDownload(job *DownloadJob, downloadURL string, client *client.Client,
|
||||
return
|
||||
}
|
||||
|
||||
acceptRanges := resp.Header.Get("Accept-Ranges")
|
||||
acceptRanges := strings.ToLower(resp.Header.Get("Accept-Ranges"))
|
||||
if acceptRanges != "bytes" {
|
||||
log.Println("[INFO] Serveur ne supporte pas Range, fallback single thread")
|
||||
StartDownloadSingleThread(job, downloadURL, db, path.Path)
|
||||
// ★ passer le chemin physique
|
||||
StartDownloadSingleThread(job, downloadURL, db, diskBase)
|
||||
return
|
||||
}
|
||||
|
||||
@ -220,7 +231,6 @@ func StartDownload(job *DownloadJob, downloadURL string, client *client.Client,
|
||||
go func() {
|
||||
var lastTotal int64 = 0
|
||||
lastUpdate := time.Now()
|
||||
|
||||
ticker := time.NewTicker(1 * time.Second)
|
||||
defer ticker.Stop()
|
||||
|
||||
@ -231,12 +241,11 @@ func StartDownload(job *DownloadJob, downloadURL string, client *client.Client,
|
||||
case <-ticker.C:
|
||||
elapsed := time.Since(lastUpdate).Seconds()
|
||||
if elapsed > 0 {
|
||||
speed := int(float64(downloaded-lastTotal) / elapsed / 1024) // en Ko/s
|
||||
speed := int(float64(downloaded-lastTotal) / elapsed / 1024) // Ko/s
|
||||
lastTotal = downloaded
|
||||
lastUpdate = time.Now()
|
||||
progress := int((downloaded * 100) / size)
|
||||
|
||||
// Update en base
|
||||
db.Model(&DownloadJob{}).Where("id = ?", job.ID).Updates(map[string]interface{}{
|
||||
"progress": progress,
|
||||
"speed": speed,
|
||||
@ -257,14 +266,13 @@ func StartDownload(job *DownloadJob, downloadURL string, client *client.Client,
|
||||
end = size - 1
|
||||
}
|
||||
|
||||
tmpPath := filepath.Join(os.TempDir(), fmt.Sprintf("%s.part%d", job.ID, i))
|
||||
tmpPath := filepath.Join(os.TempDir(), fmt.Sprintf("%v.part%d", job.ID, i))
|
||||
tmpFiles[i] = tmpPath
|
||||
|
||||
wg.Add(1)
|
||||
go func(start, end int64, tmpPath string) {
|
||||
defer wg.Done()
|
||||
err := downloadSegment(downloadURL, start, end, tmpPath, progressChan)
|
||||
if err != nil {
|
||||
if err := downloadSegment(downloadURL, start, end, tmpPath, progressChan); err != nil {
|
||||
log.Printf("[ERROR] Segment %d-%d échoué : %v\n", start, end, err)
|
||||
}
|
||||
}(start, end, tmpPath)
|
||||
@ -273,9 +281,10 @@ func StartDownload(job *DownloadJob, downloadURL string, client *client.Client,
|
||||
wg.Wait()
|
||||
close(done)
|
||||
|
||||
// Fusion
|
||||
// Fusion vers destination finale
|
||||
safeName := SanitizeFileName(job.Name)
|
||||
finalPath := generateUniqueFilePath(path.Path, safeName)
|
||||
// ★ utilise le dossier physique
|
||||
finalPath := generateUniqueFilePath(diskBase, safeName)
|
||||
|
||||
out, err := os.Create(finalPath)
|
||||
if err != nil {
|
||||
@ -290,24 +299,26 @@ func StartDownload(job *DownloadJob, downloadURL string, client *client.Client,
|
||||
UpdateJobStatus(job.ID, "failed", db)
|
||||
return
|
||||
}
|
||||
io.Copy(out, part)
|
||||
part.Close()
|
||||
os.Remove(tmpPath)
|
||||
_, _ = io.Copy(out, part)
|
||||
_ = part.Close()
|
||||
_ = os.Remove(tmpPath)
|
||||
}
|
||||
|
||||
// Post-traitement selon extension
|
||||
ext := strings.ToLower(filepath.Ext(finalPath))
|
||||
videoExts := map[string]bool{".mkv": true, ".avi": true, ".mp4": true}
|
||||
|
||||
if !videoExts[ext] {
|
||||
switch ext {
|
||||
case ".zip":
|
||||
if err := unzip(finalPath, path.Path); err != nil {
|
||||
// ★ extraire dans le dossier physique
|
||||
if err := unzip(finalPath, diskBase); err != nil {
|
||||
log.Printf("[ERROR] Décompression ZIP échouée : %v\n", err)
|
||||
UpdateJobStatus(job.ID, "failed", db)
|
||||
return
|
||||
}
|
||||
case ".rar":
|
||||
if err := unrarExtract(finalPath, path.Path); err != nil {
|
||||
if err := unrarExtract(finalPath, diskBase); err != nil {
|
||||
log.Printf("[ERROR] Décompression RAR échouée : %v\n", err)
|
||||
UpdateJobStatus(job.ID, "failed", db)
|
||||
return
|
||||
@ -322,6 +333,7 @@ func StartDownload(job *DownloadJob, downloadURL string, client *client.Client,
|
||||
log.Printf("[OK] Fichier téléchargé : %s\n", finalPath)
|
||||
}
|
||||
|
||||
|
||||
// generateUniqueFilePath ajoute un suffixe si le fichier existe déjà
|
||||
func generateUniqueFilePath(basePath, fileName string) string {
|
||||
finalPath := filepath.Join(basePath, fileName)
|
||||
@ -346,6 +358,25 @@ func generateUniqueFilePath(basePath, fileName string) string {
|
||||
func StartDownloadSingleThread(job *DownloadJob, downloadURL string, db *gorm.DB, basePath string) {
|
||||
UpdateJobStatus(job.ID, "running", db)
|
||||
|
||||
// --- Normalise le chemin disque ---
|
||||
// Si basePath est "Film" (logique BDD), on le préfixe par "upload/".
|
||||
// Si on te passe déjà "upload/Film" ou un chemin absolu, on le garde.
|
||||
diskBase := basePath
|
||||
clean := filepath.Clean(basePath)
|
||||
if !filepath.IsAbs(clean) &&
|
||||
clean != "upload" &&
|
||||
!strings.HasPrefix(clean, "upload"+string(os.PathSeparator)) {
|
||||
diskBase = filepath.Join("upload", clean)
|
||||
}
|
||||
|
||||
// Créer le répertoire si nécessaire
|
||||
if err := os.MkdirAll(diskBase, 0o755); err != nil {
|
||||
log.Printf("[ERROR] Création du dossier %s échouée : %v\n", diskBase, err)
|
||||
UpdateJobStatus(job.ID, "failed", db)
|
||||
return
|
||||
}
|
||||
|
||||
// Lance le téléchargement
|
||||
resp, err := http.Get(downloadURL)
|
||||
if err != nil {
|
||||
log.Printf("[ERROR] Téléchargement échoué : %v\n", err)
|
||||
@ -360,14 +391,7 @@ func StartDownloadSingleThread(job *DownloadJob, downloadURL string, db *gorm.DB
|
||||
return
|
||||
}
|
||||
|
||||
// Créer le répertoire si nécessaire
|
||||
if err := os.MkdirAll(basePath, os.ModePerm); err != nil {
|
||||
log.Printf("[ERROR] Création du dossier %s échouée : %v\n", basePath, err)
|
||||
UpdateJobStatus(job.ID, "failed", db)
|
||||
return
|
||||
}
|
||||
|
||||
destPath := filepath.Join(basePath, SanitizeFileName(job.Name))
|
||||
destPath := filepath.Join(diskBase, SanitizeFileName(job.Name))
|
||||
outFile, err := os.Create(destPath)
|
||||
if err != nil {
|
||||
log.Printf("[ERROR] Impossible de créer le fichier : %v\n", err)
|
||||
@ -376,7 +400,7 @@ func StartDownloadSingleThread(job *DownloadJob, downloadURL string, db *gorm.DB
|
||||
}
|
||||
defer outFile.Close()
|
||||
|
||||
// Calcul taille totale
|
||||
// Taille totale pour progression
|
||||
totalSize := resp.ContentLength
|
||||
if totalSize <= 0 && job.Size > 0 {
|
||||
totalSize = job.Size
|
||||
@ -387,7 +411,7 @@ func StartDownloadSingleThread(job *DownloadJob, downloadURL string, db *gorm.DB
|
||||
lastUpdate := time.Now()
|
||||
|
||||
for {
|
||||
n, err := resp.Body.Read(buf)
|
||||
n, readErr := resp.Body.Read(buf)
|
||||
if n > 0 {
|
||||
if _, writeErr := outFile.Write(buf[:n]); writeErr != nil {
|
||||
log.Printf("[ERROR] Écriture échouée : %v\n", writeErr)
|
||||
@ -396,17 +420,17 @@ func StartDownloadSingleThread(job *DownloadJob, downloadURL string, db *gorm.DB
|
||||
}
|
||||
downloaded += int64(n)
|
||||
}
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
if readErr != nil {
|
||||
if readErr == io.EOF {
|
||||
break
|
||||
}
|
||||
log.Printf("[ERROR] Erreur de lecture : %v\n", err)
|
||||
log.Printf("[ERROR] Erreur de lecture : %v\n", readErr)
|
||||
UpdateJobStatus(job.ID, "failed", db)
|
||||
return
|
||||
}
|
||||
|
||||
// Mise à jour de la progression
|
||||
if time.Since(lastUpdate) > 500*time.Millisecond && totalSize > 0 {
|
||||
// Mise à jour de la progression (toutes les 500ms)
|
||||
if totalSize > 0 && time.Since(lastUpdate) > 500*time.Millisecond {
|
||||
progress := int((downloaded * 100) / totalSize)
|
||||
UpdateJobProgress(job.ID, progress, db)
|
||||
lastUpdate = time.Now()
|
||||
@ -418,6 +442,7 @@ func StartDownloadSingleThread(job *DownloadJob, downloadURL string, db *gorm.DB
|
||||
log.Printf("[OK] Fichier téléchargé (single) : %s\n", destPath)
|
||||
}
|
||||
|
||||
|
||||
func downloadSegment(url string, start, end int64, dest string, progressChan chan<- int64) error {
|
||||
req, _ := http.NewRequest("GET", url, nil)
|
||||
req.Header.Set("Range", fmt.Sprintf("bytes=%d-%d", start, end))
|
||||
|
||||
Loading…
Reference in New Issue
Block a user