Prevent stale torrents

This commit is contained in:
Ben Adrian Sarmiento
2024-06-28 21:10:31 +02:00
parent 7cd8c9e5c9
commit c781a5fc7c
5 changed files with 9 additions and 121 deletions

View File

@@ -31,7 +31,6 @@ type RootResponse struct {
Logs string `json:"logs"` Logs string `json:"logs"`
UserInfo *realdebrid.User `json:"user_info"` UserInfo *realdebrid.User `json:"user_info"`
APITraffic uint64 `json:"traffic_from_api"` APITraffic uint64 `json:"traffic_from_api"`
RequestedMB uint64 `json:"requested_mb"`
ServedMB uint64 `json:"served_mb"` ServedMB uint64 `json:"served_mb"`
LibrarySize int `json:"library_size"` // Number of torrents in the library LibrarySize int `json:"library_size"` // Number of torrents in the library
TorrentsToRepair string `json:"repair_queue"` // List of torrents in the repair queue TorrentsToRepair string `json:"repair_queue"` // List of torrents in the repair queue
@@ -103,7 +102,6 @@ func (zr *Handlers) generateResponse(resp http.ResponseWriter, req *http.Request
Logs: fmt.Sprintf("//%s/logs/", req.Host), Logs: fmt.Sprintf("//%s/logs/", req.Host),
UserInfo: userInfo, UserInfo: userInfo,
APITraffic: uint64(trafficFromAPI), APITraffic: uint64(trafficFromAPI),
RequestedMB: bToMb(zr.downloader.RequestedBytes.Load()),
ServedMB: bToMb(zr.downloader.TotalBytes.Load()), ServedMB: bToMb(zr.downloader.TotalBytes.Load()),
LibrarySize: allTorrents.Count(), LibrarySize: allTorrents.Count(),
TorrentsToRepair: repairQueueStr, TorrentsToRepair: repairQueueStr,
@@ -193,7 +191,7 @@ func (zr *Handlers) handleHome(resp http.ResponseWriter, req *http.Request) {
response.Logs, response.Logs,
) )
denominator := response.RequestedMB denominator := bToMb(response.APITraffic - zr.trafficOnStartup.Load())
if denominator == 0 { if denominator == 0 {
denominator = 1 denominator = 1
} }
@@ -234,17 +232,13 @@ func (zr *Handlers) handleHome(resp http.ResponseWriter, req *http.Request) {
<td>Traffic Logged</td> <td>Traffic Logged</td>
<td colspan="2">%d MB (%d MB added)</td> <td colspan="2">%d MB (%d MB added)</td>
</tr> </tr>
<tr>
<td>Traffic Requested</td>
<td colspan="2">%d MB</td>
</tr>
<tr> <tr>
<td>Traffic Served</td> <td>Traffic Served</td>
<td colspan="2">%d MB</td> <td colspan="2">%d MB</td>
</tr> </tr>
<tr> <tr>
<td>Traffic Efficiency</td> <td>Traffic Efficiency</td>
<td colspan="2">%d%% (wasted %d MB)</td> <td colspan="2">%d%% (wasted %d MB) disclaimer: this assumes all RD traffic comes from this zurg instance</td>
</tr>`, </tr>`,
response.LibrarySize, response.LibrarySize,
response.MemAlloc, response.MemAlloc,
@@ -254,10 +248,9 @@ func (zr *Handlers) handleHome(resp http.ResponseWriter, req *http.Request) {
response.PID, response.PID,
bToMb(response.APITraffic), bToMb(response.APITraffic),
bToMb(response.APITraffic-zr.trafficOnStartup.Load()), bToMb(response.APITraffic-zr.trafficOnStartup.Load()),
response.RequestedMB,
response.ServedMB, response.ServedMB,
efficiency, efficiency,
response.RequestedMB-response.ServedMB, bToMb(response.APITraffic-zr.trafficOnStartup.Load())-response.ServedMB,
) )
out += fmt.Sprintf(` out += fmt.Sprintf(`

View File

@@ -175,7 +175,7 @@ func (t *TorrentManager) getMoreInfo(rdTorrent realdebrid.Torrent) *realdebrid.T
var err error var err error
info, err = t.rd.GetTorrentInfo(rdTorrent.ID) info, err = t.rd.GetTorrentInfo(rdTorrent.ID)
if err != nil { if err != nil {
t.log.Warnf("Cannot get info for id=%s: %v", rdTorrent.ID, err) t.log.Warnf("Cannot get info for torrent %s (id=%s): %v", rdTorrent.Name, rdTorrent.ID, err)
return nil return nil
} }
t.writeInfoToFile(info) t.writeInfoToFile(info)

View File

@@ -2,11 +2,9 @@ package universal
import ( import (
"context" "context"
"fmt"
"io" "io"
"net/http" "net/http"
"path/filepath" "path/filepath"
"strconv"
"strings" "strings"
"sync/atomic" "sync/atomic"
"time" "time"
@@ -20,10 +18,9 @@ import (
) )
type Downloader struct { type Downloader struct {
rd *realdebrid.RealDebrid rd *realdebrid.RealDebrid
workerPool *ants.Pool workerPool *ants.Pool
RequestedBytes atomic.Uint64 TotalBytes atomic.Uint64
TotalBytes atomic.Uint64
} }
func NewDownloader(rd *realdebrid.RealDebrid, workerPool *ants.Pool) *Downloader { func NewDownloader(rd *realdebrid.RealDebrid, workerPool *ants.Pool) *Downloader {
@@ -51,7 +48,6 @@ func (dl *Downloader) StartResetBandwidthCountersJob() {
ticker := time.NewTicker(24 * time.Hour) ticker := time.NewTicker(24 * time.Hour)
for { for {
dl.rd.TokenManager.ResetAllTokens() dl.rd.TokenManager.ResetAllTokens()
dl.RequestedBytes.Store(0)
dl.TotalBytes.Store(0) dl.TotalBytes.Store(0)
<-ticker.C <-ticker.C
} }
@@ -234,14 +230,9 @@ func (dl *Downloader) streamFileToResponse(
return return
} }
// Update the download statistics // Update the download statistics
reqBytes, _ := parseRangeHeader(req.Header.Get("Range"))
if reqBytes == 0 && unrestrict != nil {
reqBytes = uint64(unrestrict.Filesize)
}
dl.RequestedBytes.Add(reqBytes)
dl.TotalBytes.Add(uint64(n)) dl.TotalBytes.Add(uint64(n))
if cfg.ShouldLogRequests() { if cfg.ShouldLogRequests() {
log.Debugf("Served %d MB of the requested %d MB of file %s (range=%s)", bToMb(uint64(n)), bToMb(reqBytes), unrestrict.Filename, req.Header.Get("Range")) log.Debugf("Served %d MB of file %s (range=%s)", bToMb(uint64(n)), unrestrict.Filename, req.Header.Get("Range"))
} }
}) })
} }
@@ -250,50 +241,6 @@ func redirect(resp http.ResponseWriter, req *http.Request, url string) {
http.Redirect(resp, req, url, http.StatusFound) http.Redirect(resp, req, url, http.StatusFound)
} }
func parseRangeHeader(rangeHeader string) (uint64, error) {
if rangeHeader == "" { // Empty header means no range request
return 0, nil
}
if !strings.HasPrefix(rangeHeader, "bytes=") {
return 0, fmt.Errorf("invalid range header format")
}
parts := strings.SplitN(rangeHeader[6:], "-", 2) // [6:] removes "bytes="
if len(parts) != 2 {
return 0, fmt.Errorf("invalid range specification")
}
var start, end uint64
var err error
// Case 1: "bytes=100-" (from byte 100 to the end)
if parts[0] != "" {
start, err = strconv.ParseUint(parts[0], 10, 64)
if err != nil {
return 0, fmt.Errorf("invalid start value: %w", err)
}
}
// Case 2: "bytes=-200" (last 200 bytes)
if parts[1] != "" {
end, err = strconv.ParseUint(parts[1], 10, 64)
if err != nil {
return 0, fmt.Errorf("invalid end value: %w", err)
}
}
// Handle "bytes=500-100" (invalid range)
if start > end {
return 0, fmt.Errorf("invalid range: start cannot be greater than end")
}
// Calculate bytes to read
bytesToRead := end - start + 1 // +1 because ranges are inclusive
return bytesToRead, nil
}
type byteCounter struct { type byteCounter struct {
totalBytes *int64 totalBytes *int64
} }

View File

@@ -55,8 +55,6 @@ func NewRealDebrid(apiClient, unrestrictClient, downloadClient *zurghttp.HTTPCli
rd.UnrestrictMap.Set(token, cmap.New[*Download]()) rd.UnrestrictMap.Set(token, cmap.New[*Download]())
} }
rd.loadCachedTorrents()
return rd return rd
} }

View File

@@ -2,10 +2,8 @@ package realdebrid
import ( import (
"fmt" "fmt"
"io"
"net/http" "net/http"
"net/url" "net/url"
"os"
"strconv" "strconv"
) )
@@ -106,7 +104,7 @@ func (rd *RealDebrid) GetTorrents(onlyOne bool) ([]Torrent, int, error) {
page += maxParallelThreads page += maxParallelThreads
} }
rd.cacheTorrents(allTorrents) rd.torrentsCache = allTorrents
return allTorrents, len(allTorrents), nil return allTorrents, len(allTorrents), nil
} }
@@ -187,51 +185,3 @@ func (rd *RealDebrid) fetchPageOfTorrents(page, limit int) fetchTorrentsResult {
err: nil, err: nil,
} }
} }
func (rd *RealDebrid) cacheTorrents(torrents []Torrent) {
filePath := "data/info/all.json"
file, err := os.Create(filePath)
if err != nil {
rd.log.Warnf("Cannot create info file %s: %v", filePath, err)
return
}
defer file.Close()
jsonData, err := json.Marshal(torrents)
if err != nil {
rd.log.Warnf("Cannot marshal torrent info: %v", err)
return
}
if _, err := file.Write(jsonData); err != nil {
rd.log.Warnf("Cannot write to info file %s: %v", filePath, err)
return
}
rd.torrentsCache = torrents
}
func (rd *RealDebrid) loadCachedTorrents() {
filePath := "data/info/all.json"
file, err := os.Open(filePath)
if err != nil {
rd.log.Warnf("Cannot open info file %s: %v", filePath, err)
return
}
defer file.Close()
jsonData, err := io.ReadAll(file)
if err != nil {
rd.log.Warnf("Cannot read info file %s: %v", filePath, err)
return
}
var torrents []Torrent
err = json.Unmarshal(jsonData, &torrents)
if err != nil {
rd.log.Warnf("Cannot unmarshal torrent info: %v", err)
return
}
rd.torrentsCache = torrents
}