Add Download Progress tracking; early errors for invalid debrid torrent status (#35)

This commit is contained in:
Mukhtar Akere
2025-01-31 23:45:49 +01:00
committed by GitHub
parent 64995d0bf3
commit 297715bf6e
9 changed files with 81 additions and 40 deletions

View File

@@ -197,9 +197,7 @@ func (r *DebridLink) CheckStatus(torrent *Torrent, isSymlink bool) (*Torrent, er
return torrent, err
}
status := torrent.Status
if status == "error" || status == "dead" || status == "magnet_error" {
return torrent, fmt.Errorf("torrent: %s has error", torrent.Name)
} else if status == "downloaded" {
if status == "downloaded" {
r.logger.Info().Msgf("Torrent: %s downloaded", torrent.Name)
if !isSymlink {
err = r.GetDownloadLinks(torrent)
@@ -216,6 +214,8 @@ func (r *DebridLink) CheckStatus(torrent *Torrent, isSymlink bool) (*Torrent, er
// Break out of the loop if the torrent is downloading.
// This is necessary to prevent infinite loop since we moved to sync downloading and async processing
break
} else {
return torrent, fmt.Errorf("torrent: %s has error", torrent.Name)
}
}

View File

@@ -183,9 +183,7 @@ func (r *RealDebrid) CheckStatus(torrent *Torrent, isSymlink bool) (*Torrent, er
torrent.Status = status
torrent.Debrid = r
downloadingStatus := []string{"downloading", "magnet_conversion", "queued", "compressing", "uploading"}
if status == "error" || status == "dead" || status == "magnet_error" {
return torrent, fmt.Errorf("torrent: %s has error: %s", torrent.Name, status)
} else if status == "waiting_files_selection" {
if status == "waiting_files_selection" {
files := GetTorrentFiles(data)
torrent.Files = files
if len(files) == 0 {
@@ -222,6 +220,8 @@ func (r *RealDebrid) CheckStatus(torrent *Torrent, isSymlink bool) (*Torrent, er
// Break out of the loop if the torrent is downloading.
// This is necessary to prevent infinite loop since we moved to sync downloading and async processing
break
} else {
return torrent, fmt.Errorf("torrent: %s has error: %s", torrent.Name, status)
}
}

View File

@@ -206,9 +206,7 @@ func (r *Torbox) CheckStatus(torrent *Torrent, isSymlink bool) (*Torrent, error)
return tb, err
}
status := torrent.Status
if status == "error" || status == "dead" || status == "magnet_error" {
return torrent, fmt.Errorf("torrent: %s has error", torrent.Name)
} else if status == "downloaded" {
if status == "downloaded" {
r.logger.Info().Msgf("Torrent: %s downloaded", torrent.Name)
if !isSymlink {
err = r.GetDownloadLinks(torrent)
@@ -225,6 +223,8 @@ func (r *Torbox) CheckStatus(torrent *Torrent, isSymlink bool) (*Torrent, error)
// Break out of the loop if the torrent is downloading.
// This is necessary to prevent infinite loop since we moved to sync downloading and async processing
break
} else {
return torrent, fmt.Errorf("torrent: %s has error", torrent.Name)
}
}

View File

@@ -6,6 +6,7 @@ import (
"github.com/sirrobot01/debrid-blackhole/pkg/arr"
"os"
"path/filepath"
"sync"
)
type Arr struct {
@@ -45,8 +46,10 @@ type Torrent struct {
Links []string `json:"links"`
DownloadLinks []TorrentDownloadLinks `json:"download_links"`
Debrid Service
Arr *arr.Arr
Debrid Service `json:"-"`
Arr *arr.Arr `json:"arr"`
Mu sync.Mutex `json:"-"`
SizeDownloaded int64 `json:"-"` // This is used for local download
}
type TorrentDownloadLinks struct {

View File

@@ -2,7 +2,6 @@ package downloaders
import (
"crypto/tls"
"fmt"
"github.com/cavaliergopher/grab/v3"
"net/http"
"time"
@@ -21,35 +20,37 @@ func GetGrabClient() *grab.Client {
}
}
func NormalGrab(client *grab.Client, url, filename string) error {
func NormalGrab(client *grab.Client, url, filename string, progressCallback func(int64)) error {
req, err := grab.NewRequest(filename, url)
if err != nil {
return err
}
resp := client.Do(req)
if err := resp.Err(); err != nil {
return err
}
t := time.NewTicker(2 * time.Second)
t := time.NewTicker(time.Second)
defer t.Stop()
var lastReported int64
Loop:
for {
select {
case <-t.C:
fmt.Printf(" %s: transferred %d / %d bytes (%.2f%%)",
resp.Filename,
resp.BytesComplete(),
resp.Size(),
100*resp.Progress())
current := resp.BytesComplete()
if current != lastReported {
if progressCallback != nil {
progressCallback(current - lastReported)
}
lastReported = current
}
case <-resp.Done:
// download is complete
break Loop
}
}
if err := resp.Err(); err != nil {
return err
// Report final bytes
if progressCallback != nil {
progressCallback(resp.BytesComplete() - lastReported)
}
return nil
return resp.Err()
}

View File

@@ -96,8 +96,6 @@
} else {
alert(`Successfully added ${result.results.length} torrents!`);
}
document.getElementById('magnetURI').value = '';
} catch (error) {
alert(`Error adding downloads: ${error.message}`);
} finally {

View File

@@ -11,7 +11,8 @@ import (
"time"
)
func (q *QBit) processManualFiles(debridTorrent *debrid.Torrent) (string, error) {
func (q *QBit) ProcessManualFile(torrent *Torrent) (string, error) {
debridTorrent := torrent.DebridTorrent
q.logger.Info().Msgf("Downloading %d files...", len(debridTorrent.DownloadLinks))
torrentPath := common.RemoveExtension(debridTorrent.OriginalFilename)
parent := common.RemoveInvalidChars(filepath.Join(q.DownloadFolder, debridTorrent.Arr.Name, torrentPath))
@@ -20,14 +21,38 @@ func (q *QBit) processManualFiles(debridTorrent *debrid.Torrent) (string, error)
// add previous error to the error and return
return "", fmt.Errorf("failed to create directory: %s: %v", parent, err)
}
q.downloadFiles(debridTorrent, parent)
q.downloadFiles(torrent, parent)
return torrentPath, nil
}
func (q *QBit) downloadFiles(debridTorrent *debrid.Torrent, parent string) {
func (q *QBit) downloadFiles(torrent *Torrent, parent string) {
debridTorrent := torrent.DebridTorrent
var wg sync.WaitGroup
semaphore := make(chan struct{}, 5)
client := downloaders.GetHTTPClient()
totalSize := int64(0)
for _, file := range debridTorrent.Files {
totalSize += file.Size
}
debridTorrent.Mu.Lock()
debridTorrent.SizeDownloaded = 0 // Reset downloaded bytes
debridTorrent.Progress = 0 // Reset progress
debridTorrent.Mu.Unlock()
client := downloaders.GetGrabClient()
progressCallback := func(downloaded int64) {
debridTorrent.Mu.Lock()
defer debridTorrent.Mu.Unlock()
torrent.Mu.Lock()
defer torrent.Mu.Unlock()
// Update total downloaded bytes
debridTorrent.SizeDownloaded += downloaded
// Calculate overall progress
if totalSize > 0 {
debridTorrent.Progress = float64(debridTorrent.SizeDownloaded) / float64(totalSize) * 100
}
q.UpdateTorrentMin(torrent, debridTorrent)
}
for _, link := range debridTorrent.DownloadLinks {
if link.DownloadLink == "" {
q.logger.Info().Msgf("No download link found for %s", link.Filename)
@@ -38,11 +63,19 @@ func (q *QBit) downloadFiles(debridTorrent *debrid.Torrent, parent string) {
go func(link debrid.TorrentDownloadLinks) {
defer wg.Done()
defer func() { <-semaphore }()
err := downloaders.NormalHTTP(client, link.DownloadLink, filepath.Join(parent, link.Filename))
filename := link.Filename
err := downloaders.NormalGrab(
client,
link.DownloadLink,
filepath.Join(parent, filename),
progressCallback,
)
if err != nil {
q.logger.Info().Msgf("Error downloading %s: %v", link.DownloadLink, err)
q.logger.Error().Msgf("Failed to download %s: %v", filename, err)
} else {
q.logger.Info().Msgf("Downloaded %s successfully", link.DownloadLink)
q.logger.Info().Msgf("Downloaded %s", filename)
}
}(link)
}
@@ -50,7 +83,8 @@ func (q *QBit) downloadFiles(debridTorrent *debrid.Torrent, parent string) {
q.logger.Info().Msgf("Downloaded all files for %s", debridTorrent.Name)
}
func (q *QBit) ProcessSymlink(debridTorrent *debrid.Torrent) (string, error) {
func (q *QBit) ProcessSymlink(torrent *Torrent) (string, error) {
debridTorrent := torrent.DebridTorrent
var wg sync.WaitGroup
files := debridTorrent.Files
ready := make(chan debrid.TorrentFile, len(files))

View File

@@ -1,6 +1,9 @@
package shared
import "github.com/sirrobot01/debrid-blackhole/pkg/debrid"
import (
"github.com/sirrobot01/debrid-blackhole/pkg/debrid"
"sync"
)
type BuildInfo struct {
Libtorrent string `json:"libtorrent"`
@@ -219,6 +222,8 @@ type Torrent struct {
UploadedSession int64 `json:"uploaded_session,omitempty"`
Upspeed int `json:"upspeed,omitempty"`
Source string `json:"source,omitempty"`
Mu sync.Mutex `json:"-"`
}
func (t *Torrent) IsReady() bool {

View File

@@ -112,9 +112,9 @@ func (q *QBit) ProcessFiles(torrent *Torrent, debridTorrent *debrid.Torrent, arr
)
debridTorrent.Arr = arr
if isSymlink {
torrentPath, err = q.ProcessSymlink(debridTorrent)
torrentPath, err = q.ProcessSymlink(torrent)
} else {
torrentPath, err = q.processManualFiles(debridTorrent)
torrentPath, err = q.ProcessManualFile(torrent)
}
if err != nil {
q.MarkAsFailed(torrent)