package realdebrid import ( "net/http" "strings" "time" ) func (rd *RealDebrid) UnrestrictUntilOk(link string) *UnrestrictResponse { if !strings.HasPrefix(link, "http") { return nil } unrestrictFn := func(link string) (*UnrestrictResponse, error) { return rd.UnrestrictLink(link) } return retryUntilOk(func() (*UnrestrictResponse, error) { return unrestrictFn(link) }) } func (rd *RealDebrid) canFetchFirstByte(url string) bool { const maxAttempts = 3 for i := 0; i < maxAttempts; i++ { // Create a new HTTP request req, err := http.NewRequest("GET", url, nil) if err != nil { continue } // 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) } }