Optimize streaming from Real-Debrid

This commit is contained in:
Ben Adrian Sarmiento
2024-06-27 12:35:44 +02:00
parent bd1a163002
commit 7a7a79e882
6 changed files with 52 additions and 36 deletions

View File

@@ -68,28 +68,28 @@ func (dl *Downloader) DownloadFile(
) {
torrents, ok := torMgr.DirectoryMap.Get(directory)
if !ok {
log.Warnf("Cannot find directory %s", directory)
log.Errorf("Cannot find directory %s", directory)
http.Error(resp, "File not found", http.StatusNotFound)
return
}
torrent, ok := torrents.Get(torrentName)
if !ok {
log.Warnf("Cannot find torrent %sfrom path %s", torrentName, req.URL.Path)
log.Errorf("Cannot find torrent %s from path %s", torrentName, req.URL.Path)
http.Error(resp, "File not found", http.StatusNotFound)
return
}
file, ok := torrent.SelectedFiles.Get(fileName)
if !ok || !file.State.Is("ok_file") {
// log.Warnf("Cannot find file %s from path %s", fileName, req.URL.Path)
log.Errorf("Cannot find file %s from path %s", fileName, req.URL.Path)
http.Error(resp, "File not found", http.StatusNotFound)
return
}
unrestrict, err := torMgr.UnrestrictFile(file, cfg.ShouldServeFromRclone())
if dlErr, ok := err.(*zurghttp.DownloadErrorResponse); ok && dlErr.Message == "bytes_limit_reached" {
// log.Warnf("Your account has reached the bandwidth limit, please try again after 12AM CET")
// log.Errorf("Your account has reached the bandwidth limit, please try again after 12AM CET")
http.Error(resp, "File is not available (bandwidth limit reached)", http.StatusBadRequest)
return
}
@@ -133,7 +133,7 @@ func (dl *Downloader) DownloadLink(
// log.Debugf("Opening file %s (%s)", fileName, link)
unrestrict, err := torMgr.UnrestrictLink(link, cfg.ShouldServeFromRclone())
if dlErr, ok := err.(*zurghttp.DownloadErrorResponse); ok && dlErr.Message == "bytes_limit_reached" {
// log.Warnf("Your account has reached the bandwidth limit, please try again after 12AM CET")
// log.Errorf("Your account has reached the bandwidth limit, please try again after 12AM CET")
http.Error(resp, "Link is not available (bandwidth limit reached)", http.StatusBadRequest)
return
}
@@ -172,18 +172,16 @@ func (dl *Downloader) streamFileToResponse(
// Add the range header if it exists
if req.Header.Get("Range") != "" {
dlReq.Header.Add("Range", req.Header.Get("Range"))
// log.Debugf("Serving file %s: %s", unrestrict.Filename, req.Header.Get("Range"))
}
// Perform the request
downloadResp, err := dl.client.Do(dlReq)
if dlErr, ok := err.(*zurghttp.DownloadErrorResponse); ok && dlErr.Message == "bytes_limit_reached" {
// log.Warnf("Your account has reached the bandwidth limit, please try again after 12AM CET")
// log.Errorf("Your account has reached the bandwidth limit, please try again after 12AM CET")
http.Error(resp, "File is not available (bandwidth limit reached)", http.StatusBadRequest)
return
}
if err != nil {
log.Warnf("Cannot download file %s: %v", unrestrict.Download, err)
log.Errorf("Cannot download file %s: %v", unrestrict.Download, err)
if file != nil && file.State.Event(context.Background(), "break_file") == nil {
torMgr.EnqueueForRepair(torrent)
}
@@ -194,7 +192,7 @@ func (dl *Downloader) streamFileToResponse(
// Check if the download was not successful
if downloadResp.StatusCode != http.StatusOK && downloadResp.StatusCode != http.StatusPartialContent {
log.Warnf("Received a %s status code for file %s", downloadResp.Status, unrestrict.Filename)
log.Errorf("Received a %s status code for file %s", downloadResp.Status, unrestrict.Filename)
if file != nil && file.State.Event(context.Background(), "break_file") == nil {
torMgr.EnqueueForRepair(torrent)
}
@@ -202,15 +200,43 @@ func (dl *Downloader) streamFileToResponse(
return
}
// Copy the content-range header from the download response to the response
if cr := downloadResp.Header.Get("Content-Range"); cr != "" {
resp.Header().Set("Content-Range", cr)
}
buf := make([]byte, cfg.GetNetworkBufferSize())
n, _ := io.CopyBuffer(resp, downloadResp.Body, buf)
var n int64
if cfg.ShouldLogRequests() {
var totalBytes int64
ticker := time.NewTicker(60 * time.Second)
done := make(chan bool)
go func() {
for {
select {
case <-ticker.C:
mbps := float64(totalBytes*8) / 60_000_000
if mbps > 0 {
log.Debugf("%s | %.2f MB/s", dlReq.URL, mbps)
}
totalBytes = 0
case <-done:
ticker.Stop()
return
}
}
}()
defer func() {
done <- true
}()
n, _ = io.Copy(io.MultiWriter(resp, &byteCounter{&totalBytes}), downloadResp.Body)
} else {
n, _ = io.Copy(resp, downloadResp.Body)
}
dl.workerPool.Submit(func() {
if n == 0 {
return
}
// Update the download statistics
reqBytes, _ := parseRangeHeader(req.Header.Get("Range"))
if reqBytes == 0 && unrestrict != nil {
@@ -272,6 +298,16 @@ func parseRangeHeader(rangeHeader string) (uint64, error) {
return bytesToRead, nil
}
type byteCounter struct {
totalBytes *int64
}
func (bc *byteCounter) Write(p []byte) (int, error) {
n := len(p)
*bc.totalBytes += int64(n)
return n, nil
}
func bToMb(b uint64) uint64 {
return b / 1024 / 1024
}