This commit is contained in:
Ben Sarmiento
2023-11-27 21:50:00 +01:00
parent a7623de410
commit c8334ecb3b
15 changed files with 277 additions and 221 deletions

View File

@@ -19,7 +19,7 @@ type RealDebrid struct {
client *zurghttp.HTTPClient
}
func NewRealDebrid(accessToken string, client *zurghttp.HTTPClient, log *zap.SugaredLogger) *RealDebrid {
func NewRealDebrid(client *zurghttp.HTTPClient, log *zap.SugaredLogger) *RealDebrid {
return &RealDebrid{
log: log,
client: client,
@@ -69,7 +69,7 @@ func (rd *RealDebrid) GetTorrents(customLimit int) ([]Torrent, int, error) {
page := 1
limit := customLimit
if limit == 0 {
limit = 2500
limit = 1000
}
totalCount := 0
@@ -263,7 +263,7 @@ func (rd *RealDebrid) GetActiveTorrentCount() (*ActiveTorrentCountResponse, erro
return &response, nil
}
func (rd *RealDebrid) UnrestrictLink(link string) (*UnrestrictResponse, error) {
func (rd *RealDebrid) UnrestrictLink(link string, checkFirstByte bool) (*UnrestrictResponse, error) {
data := url.Values{}
data.Set("link", link)
@@ -283,6 +283,11 @@ func (rd *RealDebrid) UnrestrictLink(link string) (*UnrestrictResponse, error) {
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
rd.log.Errorf("Unrestrict link request returned status code %d for link %s", resp.StatusCode, link)
// return nil, fmt.Errorf("unrestrict link request returned status code %d so likely it has expired", resp.StatusCode)
}
body, err := io.ReadAll(resp.Body)
if err != nil {
// rd.log.Errorf("Error when reading the body of unrestrict link response: %v", err)
@@ -296,7 +301,7 @@ func (rd *RealDebrid) UnrestrictLink(link string) (*UnrestrictResponse, error) {
return nil, fmt.Errorf("undecodable response so likely it has expired")
}
if !rd.canFetchFirstByte(response.Download) {
if checkFirstByte && !rd.canFetchFirstByte(response.Download) {
return nil, fmt.Errorf("can't fetch first byte")
}

View File

@@ -3,91 +3,40 @@ package realdebrid
import (
"net/http"
"strings"
"time"
)
func (rd *RealDebrid) UnrestrictUntilOk(link string) *UnrestrictResponse {
func (rd *RealDebrid) UnrestrictUntilOk(link string, serveFromRclone bool) *UnrestrictResponse {
if !strings.HasPrefix(link, "http") {
return nil
}
unrestrictFn := func(link string) (*UnrestrictResponse, error) {
return rd.UnrestrictLink(link)
resp, _ := rd.UnrestrictLink(link, serveFromRclone)
if resp != nil {
return resp
}
return retryUntilOk(func() (*UnrestrictResponse, error) {
return unrestrictFn(link)
})
return nil
}
func (rd *RealDebrid) canFetchFirstByte(url string) bool {
const maxAttempts = 3
req, err := http.NewRequest("GET", url, nil)
if err != nil {
return false
}
for i := 0; i < maxAttempts; i++ {
// Create a new HTTP request
req, err := http.NewRequest("GET", url, nil)
if err != nil {
continue
req.Header.Set("Range", "bytes=0-0")
resp, err := rd.client.Do(req)
if err != nil {
return false
}
defer resp.Body.Close()
// If server supports partial content
if resp.StatusCode == http.StatusPartialContent || resp.StatusCode == http.StatusOK {
buffer := make([]byte, 1)
_, err = resp.Body.Read(buffer)
if err == nil {
return true
}
// Set the Range header to request only the first byte
req.Header.Set("Range", "bytes=0-0")
// TODO set a proper client
resp, err := rd.client.Do(req)
if err != nil {
time.Sleep(1 * time.Second) // Add a delay before the next retry
continue
}
defer resp.Body.Close()
// If server supports partial content
if resp.StatusCode == http.StatusPartialContent {
buffer := make([]byte, 1)
_, err := resp.Body.Read(buffer)
if err == nil {
return true
}
} else if resp.StatusCode == http.StatusOK {
// If server doesn't support partial content, try reading the first byte and immediately close
buffer := make([]byte, 1)
_, err = resp.Body.Read(buffer)
if err == nil {
return true
}
}
time.Sleep(500 * time.Millisecond) // Add a delay before the next retry
}
return false
}
func retryUntilOk[T any](fn func() (T, error)) T {
// const initialDelay = 1 * time.Second
// const maxDelay = 128 * time.Second
const maxRetries = 2 // Maximum retries for non-429 errors
var result T
var err error
var retryCount int
for {
result, err = fn()
if err == nil {
return result
}
if strings.Contains(err.Error(), "first byte") || strings.Contains(err.Error(), "expired") {
return result
}
if !strings.Contains(err.Error(), "429") {
retryCount++
if retryCount >= maxRetries {
// If we've reached the maximum retries for errors other than 429, return the last result.
return result
}
}
// Calculate delay with exponential backoff
// delay := time.Duration(math.Min(float64(initialDelay)*math.Pow(2, float64(retryCount)), float64(maxDelay)))
delay := 500 * time.Millisecond
time.Sleep(delay)
}
}